So far on purging broadcast and ogm queues we temporarily give up the
spin lock of these queues to be able to cancel any scheduled forwarding
work. However this is unsafe and can lead to a general protection error
in batadv_purge_outstanding_packets().
With this patch we split the queue purging into two steps: First
removing forward packets from those queues and signaling the
cancelation. Secondly, we are actively canceling any scheduled
forwarding, wait for any running forwarding to finish and only free a
forw_packet afterwards.
Signed-off-by: Linus Lüssing <linus.luessing(a)web.de>
---
Fixes issue #168
send.c | 117 ++++++++++++++++++++++++++++++++++++++-------------------------
types.h | 1 +
2 files changed, 71 insertions(+), 47 deletions(-)
diff --git a/send.c b/send.c
index 0a0bb45..f93476b 100644
--- a/send.c
+++ b/send.c
@@ -245,6 +245,10 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
bat_priv = netdev_priv(soft_iface);
spin_lock_bh(&bat_priv->forw_bcast_list_lock);
+ if (hlist_unhashed(&forw_packet->list)) {
+ spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
+ return;
+ }
hlist_del(&forw_packet->list);
spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
@@ -293,6 +297,10 @@ void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work)
delayed_work);
bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
spin_lock_bh(&bat_priv->forw_bat_list_lock);
+ if (hlist_unhashed(&forw_packet->list)) {
+ spin_unlock_bh(&bat_priv->forw_bat_list_lock);
+ return;
+ }
hlist_del(&forw_packet->list);
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
@@ -316,13 +324,68 @@ out:
batadv_forw_packet_free(forw_packet);
}
+/**
+ * batadv_cancel_packets - Cancels a list of forward packets
+ * @forw_list: The to be canceled forward packets
+ * @canceled_list: The backup list.
+ *
+ * This canceles any scheduled forwarding packet tasks in the provided
+ * forw_list. The packets are being moved from the forw_list to the
+ * canceled_list afterwards to unhash the forward packet list pointer,
+ * allowing any already running task to notice the cancelation.
+ */
+static void batadv_cancel_packets(struct hlist_head *forw_list,
+ struct hlist_head *canceled_list,
+ const struct batadv_hard_iface *hard_iface)
+{
+ struct batadv_forw_packet *forw_packet;
+ struct hlist_node *tmp_node, *safe_tmp_node;
+
+ hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
+ forw_list, list) {
+ /* if purge_outstanding_packets() was called with an argument
+ * we delete only packets belonging to the given interface
+ */
+ if ((hard_iface) &&
+ (forw_packet->if_incoming != hard_iface))
+ continue;
+
+ hlist_del_init(&forw_packet->list);
+ hlist_add_head(&forw_packet->canceled_list, canceled_list);
+ }
+}
+
+/**
+ * batadv_canceled_packets_free - Frees canceled forward packets
+ * @head: A list of to be freed forw_packets
+ *
+ * This function canceles the scheduling of any packet in the provided list,
+ * waits for any possibly running packet forwarding thread to finish and
+ * finally, safely frees this forward packet.
+ *
+ * This function might sleep.
+ */
+static void batadv_canceled_packets_free(struct hlist_head *head)
+{
+ struct batadv_forw_packet *forw_packet;
+ struct hlist_node *tmp_node, *safe_tmp_node;
+
+ hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, head,
+ canceled_list) {
+ cancel_delayed_work_sync(&forw_packet->delayed_work);
+
+ hlist_del(&forw_packet->canceled_list);
+ batadv_forw_packet_free(forw_packet);
+ }
+}
+
void
batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
const struct batadv_hard_iface *hard_iface)
{
- struct batadv_forw_packet *forw_packet;
- struct hlist_node *tmp_node, *safe_tmp_node;
- bool pending;
+ struct hlist_head head;
+
+ INIT_HLIST_HEAD(&head);
if (hard_iface)
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
@@ -334,53 +397,13 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
/* free bcast list */
spin_lock_bh(&bat_priv->forw_bcast_list_lock);
- hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
- &bat_priv->forw_bcast_list, list) {
- /* if purge_outstanding_packets() was called with an argument
- * we delete only packets belonging to the given interface
- */
- if ((hard_iface) &&
- (forw_packet->if_incoming != hard_iface))
- continue;
-
- spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
-
- /* batadv_send_outstanding_bcast_packet() will lock the list to
- * delete the item from the list
- */
- pending = cancel_delayed_work_sync(&forw_packet->delayed_work);
- spin_lock_bh(&bat_priv->forw_bcast_list_lock);
-
- if (pending) {
- hlist_del(&forw_packet->list);
- batadv_forw_packet_free(forw_packet);
- }
- }
+ batadv_cancel_packets(&bat_priv->forw_bcast_list, &head, hard_iface);
spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
/* free batman packet list */
spin_lock_bh(&bat_priv->forw_bat_list_lock);
- hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
- &bat_priv->forw_bat_list, list) {
- /* if purge_outstanding_packets() was called with an argument
- * we delete only packets belonging to the given interface
- */
- if ((hard_iface) &&
- (forw_packet->if_incoming != hard_iface))
- continue;
-
- spin_unlock_bh(&bat_priv->forw_bat_list_lock);
-
- /* send_outstanding_bat_packet() will lock the list to
- * delete the item from the list
- */
- pending = cancel_delayed_work_sync(&forw_packet->delayed_work);
- spin_lock_bh(&bat_priv->forw_bat_list_lock);
-
- if (pending) {
- hlist_del(&forw_packet->list);
- batadv_forw_packet_free(forw_packet);
- }
- }
+ batadv_cancel_packets(&bat_priv->forw_bat_list, &head, hard_iface);
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
+
+ batadv_canceled_packets_free(&head);
}
diff --git a/types.h b/types.h
index aba8364..f62a35f 100644
--- a/types.h
+++ b/types.h
@@ -853,6 +853,7 @@ struct batadv_skb_cb {
*/
struct batadv_forw_packet {
struct hlist_node list;
+ struct hlist_node canceled_list;
unsigned long send_time;
uint8_t own;
struct sk_buff *skb;
--
1.7.10.4
When removing a single interface while a broadcast or ogm packet is
still pending then we will free the forward packet without releasing the
queue slots again.
This patch is supposed to fix this issue.
Signed-off-by: Linus Lüssing <linus.luessing(a)web.de>
---
send.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/send.c b/send.c
index ed7072a..2d539d6 100644
--- a/send.c
+++ b/send.c
@@ -356,6 +356,9 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
if (pending) {
hlist_del(&forw_packet->list);
+ if (!forw_packet->own)
+ atomic_inc(&bat_priv->bcast_queue_left);
+
batadv_forw_packet_free(forw_packet);
}
}
@@ -382,6 +385,9 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
if (pending) {
hlist_del(&forw_packet->list);
+ if (!forw_packet->own)
+ atomic_inc(&bat_priv->batman_queue_left);
+
batadv_forw_packet_free(forw_packet);
}
}
--
1.7.10.4
From: Mihail Costea <mihail.costea90(a)gmail.com>
Mades DAT support more types by making its data a void*, adding type field
to dat_entry and adding data_type to necessary functions.
This change is needed in order to make DAT support any type of data, like IPv6 too.
Adds generic function for transforming DAT data to string.
The function is used in order to avoid defining different debug messages
for different DAT data types. For example, if we had IPv6 as a DAT data,
then "%pI4" should be "%pI6c", but all
the other text of the debug message would be the same.
Also everything is memorized in a struct in order to avoid further
switch cases for all types.
Signed-off-by: Mihail Costea <mihail.costea90(a)gmail.com>
Signed-off-by: Stefan Popa <Stefan.A.Popa(a)intel.com>
Reviewed-by: Stefan Popa <Stefan.A.Popa(a)intel.com>
---
distributed-arp-table.c | 197 +++++++++++++++++++++++++++++++++++------------
distributed-arp-table.h | 1 +
types.h | 24 +++++-
3 files changed, 169 insertions(+), 53 deletions(-)
diff --git a/distributed-arp-table.c b/distributed-arp-table.c
index f2543c2..90565d0 100644
--- a/distributed-arp-table.c
+++ b/distributed-arp-table.c
@@ -31,9 +31,32 @@
#include "types.h"
#include "translation-table.h"
+static struct batadv_dat_type_info batadv_dat_types_info[] = {
+ {
+ .size = sizeof(__be32),
+ .str_fmt = "%pI4",
+ },
+};
+
static void batadv_dat_purge(struct work_struct *work);
/**
+ * batadv_dat_data_to_str: transforms DAT data to string
+ * @data: the DAT data
+ * @type: type of data
+ * @buf: the buf where the data string is stored
+ * @buf_len: buf length
+ *
+ * Returns buf.
+ */
+static char *batadv_dat_data_to_str(void *data, uint8_t type,
+ char *buf, size_t buf_len)
+{
+ snprintf(buf, buf_len, batadv_dat_types_info[type].str_fmt, data);
+return buf;
+}
+
+/**
* batadv_dat_start_timer - initialise the DAT periodic worker
* @bat_priv: the bat priv with all the soft interface information
*/
@@ -45,6 +68,19 @@ static void batadv_dat_start_timer(struct batadv_priv *bat_priv)
}
/**
+ * batadv_dat_entry_free_ref_rcu - free a dat entry using its rcu
+ * @rcu: the dat entry rcu
+ */
+static void batadv_dat_entry_free_ref_rcu(struct rcu_head *rcu)
+{
+ struct batadv_dat_entry *dat_entry;
+
+ dat_entry = container_of(rcu, struct batadv_dat_entry, rcu);
+ kfree(dat_entry->data);
+ kfree(dat_entry);
+}
+
+/**
* batadv_dat_entry_free_ref - decrement the dat_entry refcounter and possibly
* free it
* @dat_entry: the entry to free
@@ -52,7 +88,7 @@ static void batadv_dat_start_timer(struct batadv_priv *bat_priv)
static void batadv_dat_entry_free_ref(struct batadv_dat_entry *dat_entry)
{
if (atomic_dec_and_test(&dat_entry->refcount))
- kfree_rcu(dat_entry, rcu);
+ call_rcu(&dat_entry->rcu, batadv_dat_entry_free_ref_rcu);
}
/**
@@ -136,12 +172,21 @@ static void batadv_dat_purge(struct work_struct *work)
*
* Returns 1 if the two entries are the same, 0 otherwise.
*/
-static int batadv_compare_dat(const struct hlist_node *node, const void *data2)
+static int batadv_compare_dat(const struct hlist_node *node, const void *data2)
{
- const void *data1 = container_of(node, struct batadv_dat_entry,
- hash_entry);
+ struct batadv_dat_entry *dat_entry1 =
+ container_of(node, struct batadv_dat_entry,
+ hash_entry);
+ struct batadv_dat_entry *dat_entry2 =
+ container_of(data2,
+ struct batadv_dat_entry, data);
+ size_t data_size = batadv_dat_types_info[dat_entry1->type].size;
- return (memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0);
+ if (dat_entry1->type != dat_entry2->type)
+ return 0;
+
+ return (memcmp(dat_entry1->data, dat_entry2->data,
+ data_size) == 0 ? 1 : 0);
}
/**
@@ -198,8 +243,9 @@ static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size)
}
/**
- * batadv_hash_dat - compute the hash value for an IP address
+ * batadv_hash_dat - compute the hash value for a DAT data
* @data: data to hash
+ * @data_type: type of data
* @size: size of the hash table
*
* Returns the selected index in the hash table for the given data.
@@ -209,7 +255,8 @@ static uint32_t batadv_hash_dat(const void *data, uint32_t size)
uint32_t hash = 0;
const struct batadv_dat_entry *dat = data;
- hash = batadv_hash_bytes(hash, &dat->ip, sizeof(dat->ip));
+ hash = batadv_hash_bytes(hash, dat->data,
+ batadv_dat_types_info[dat->type].size);
hash = batadv_hash_bytes(hash, &dat->vid, sizeof(dat->vid));
hash += (hash << 3);
@@ -223,32 +270,40 @@ static uint32_t batadv_hash_dat(const void *data, uint32_t size)
* batadv_dat_entry_hash_find - look for a given dat_entry in the local hash
* table
* @bat_priv: the bat priv with all the soft interface information
- * @ip: search key
+ * @data: search key
+ * @data_type: type of data
* @vid: VLAN identifier
*
* Returns the dat_entry if found, NULL otherwise.
*/
static struct batadv_dat_entry *
-batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
- unsigned short vid)
+batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, void *data,
+ uint8_t data_type, unsigned short vid)
{
struct hlist_head *head;
struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL;
struct batadv_hashtable *hash = bat_priv->dat.hash;
- uint32_t index;
+ uint32_t index, data_size = batadv_dat_types_info[data_type].size;
if (!hash)
return NULL;
- to_find.ip = ip;
+ to_find.data = kmalloc(data_size, GFP_ATOMIC);
+ if (!to_find.data)
+ return NULL;
+ memcpy(to_find.data, data, data_size);
+ to_find.type = data_type;
to_find.vid = vid;
index = batadv_hash_dat(&to_find, hash->size);
head = &hash->table[index];
+ kfree(to_find.data);
rcu_read_lock();
hlist_for_each_entry_rcu(dat_entry, head, hash_entry) {
- if (dat_entry->ip != ip)
+ if (dat_entry->type != data_type)
+ continue;
+ if (memcmp(dat_entry->data, data, data_size))
continue;
if (!atomic_inc_not_zero(&dat_entry->refcount))
@@ -265,25 +320,30 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
/**
* batadv_dat_entry_add - add a new dat entry or update it if already exists
* @bat_priv: the bat priv with all the soft interface information
- * @ip: ipv4 to add/edit
- * @mac_addr: mac address to assign to the given ipv4
+ * @data: the data to add/edit
+ * @data_type: type of the data added to DAT
+ * @mac_addr: mac address to assign to the given data
* @vid: VLAN identifier
*/
-static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
- uint8_t *mac_addr, unsigned short vid)
+static void batadv_dat_entry_add(struct batadv_priv *bat_priv, void *data,
+ uint8_t data_type, uint8_t *mac_addr,
+ unsigned short vid)
{
struct batadv_dat_entry *dat_entry;
int hash_added;
+ char dbg_data[BATADV_DAT_DATA_MAX_LEN];
+ size_t data_size = batadv_dat_types_info[data_type].size;
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid);
+ dat_entry = batadv_dat_entry_hash_find(bat_priv, data, data_type, vid);
/* if this entry is already known, just update it */
if (dat_entry) {
if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
dat_entry->last_update = jiffies;
- batadv_dbg(BATADV_DBG_DAT, bat_priv,
- "Entry updated: %pI4 %pM (vid: %u)\n",
- &dat_entry->ip, dat_entry->mac_addr, vid);
+ batadv_dbg(BATADV_DBG_DAT, bat_priv, "Entry updated: %s %pM (vid: %u)\n",
+ batadv_dat_data_to_str(dat_entry->data, data_type,
+ dbg_data, sizeof(dbg_data)),
+ dat_entry->mac_addr, vid);
goto out;
}
@@ -291,7 +351,12 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
if (!dat_entry)
goto out;
- dat_entry->ip = ip;
+ dat_entry->data = kmalloc(data_size, GFP_ATOMIC);
+ if (!dat_entry->data)
+ goto out;
+ memcpy(dat_entry->data, data, data_size);
+
+ dat_entry->type = data_type;
dat_entry->vid = vid;
memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
dat_entry->last_update = jiffies;
@@ -307,8 +372,10 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
goto out;
}
- batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %u)\n",
- &dat_entry->ip, dat_entry->mac_addr, vid);
+ batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %s %pM (vid: %u)\n",
+ batadv_dat_data_to_str(dat_entry->data, data_type,
+ dbg_data, sizeof(dbg_data)),
+ dat_entry->mac_addr, vid);
out:
if (dat_entry)
@@ -520,7 +587,8 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
* batadv_dat_select_candidates - select the nodes which the DHT message has to
* be sent to
* @bat_priv: the bat priv with all the soft interface information
- * @ip_dst: ipv4 to look up in the DHT
+ * @data: data to look up in the DHT
+ * @data_type: type of data
*
* An originator O is selected if and only if its DHT_ID value is one of three
* closest values (from the LEFT, with wrap around if needed) then the hash
@@ -529,11 +597,15 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
* Returns the candidate array of size BATADV_DAT_CANDIDATE_NUM.
*/
static struct batadv_dat_candidate *
-batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
+batadv_dat_select_candidates(struct batadv_priv *bat_priv, void *data,
+ uint8_t data_type)
{
int select;
- batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key;
+ batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, data_key;
struct batadv_dat_candidate *res;
+ struct batadv_dat_entry to_find;
+ char dbg_data[BATADV_DAT_DATA_MAX_LEN];
+ size_t data_size = batadv_dat_types_info[data_type].size;
if (!bat_priv->orig_hash)
return NULL;
@@ -542,15 +614,23 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
if (!res)
return NULL;
- ip_key = (batadv_dat_addr_t)batadv_hash_dat(&ip_dst,
- BATADV_DAT_ADDR_MAX);
+ to_find.data = kmalloc(data_size, GFP_ATOMIC);
+ if (!to_find.data)
+ return NULL;
+ memcpy(to_find.data, data, data_size);
+ to_find.type = data_type;
+ data_key = (batadv_dat_addr_t)batadv_hash_dat(&to_find,
+ BATADV_DAT_ADDR_MAX);
+ kfree(to_find.data);
batadv_dbg(BATADV_DBG_DAT, bat_priv,
- "dat_select_candidates(): IP=%pI4 hash(IP)=%u\n", &ip_dst,
- ip_key);
+ "dat_select_candidates(): DATA=%s hash(DATA)=%u\n",
+ batadv_dat_data_to_str(data, data_type, dbg_data,
+ sizeof(dbg_data)),
+ data_key);
for (select = 0; select < BATADV_DAT_CANDIDATES_NUM; select++)
- batadv_choose_next_candidate(bat_priv, res, select, ip_key,
+ batadv_choose_next_candidate(bat_priv, res, select, data_key,
&last_max);
return res;
@@ -560,7 +640,8 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
* batadv_dat_send_data - send a payload to the selected candidates
* @bat_priv: the bat priv with all the soft interface information
* @skb: payload to send
- * @ip: the DHT key
+ * @data: the DHT key
+ * @data_type: type of data
* @packet_subtype: unicast4addr packet subtype to use
*
* This function copies the skb with pskb_copy() and is sent as unicast packet
@@ -570,8 +651,8 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
* otherwise.
*/
static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
- struct sk_buff *skb, __be32 ip,
- int packet_subtype)
+ struct sk_buff *skb, void *data,
+ uint8_t data_type, int packet_subtype)
{
int i;
bool ret = false;
@@ -579,12 +660,15 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
struct batadv_neigh_node *neigh_node = NULL;
struct sk_buff *tmp_skb;
struct batadv_dat_candidate *cand;
+ char dbg_data[BATADV_DAT_DATA_MAX_LEN];
- cand = batadv_dat_select_candidates(bat_priv, ip);
+ cand = batadv_dat_select_candidates(bat_priv, data, data_type);
if (!cand)
goto out;
- batadv_dbg(BATADV_DBG_DAT, bat_priv, "DHT_SEND for %pI4\n", &ip);
+ batadv_dbg(BATADV_DBG_DAT, bat_priv, "DHT_SEND for %s\n",
+ batadv_dat_data_to_str(data, data_type, dbg_data,
+ sizeof(dbg_data)));
for (i = 0; i < BATADV_DAT_CANDIDATES_NUM; i++) {
if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND)
@@ -754,6 +838,7 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
unsigned long last_seen_jiffies;
int last_seen_msecs, last_seen_secs, last_seen_mins;
uint32_t i;
+ char dbg_data[BATADV_DAT_DATA_MAX_LEN];
primary_if = batadv_seq_print_text_primary_if_get(seq);
if (!primary_if)
@@ -774,8 +859,12 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
last_seen_msecs = last_seen_msecs % 60000;
last_seen_secs = last_seen_msecs / 1000;
- seq_printf(seq, " * %15pI4 %14pM %6i:%02i\n",
- &dat_entry->ip, dat_entry->mac_addr,
+ seq_printf(seq, " * %15s %14pM %6i:%02i\n",
+ batadv_dat_data_to_str(dat_entry->data,
+ dat_entry->type,
+ dbg_data,
+ sizeof(dbg_data)),
+ dat_entry->mac_addr,
last_seen_mins, last_seen_secs);
}
rcu_read_unlock();
@@ -926,9 +1015,10 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
hw_src = batadv_arp_hw_src(skb, 0);
ip_dst = batadv_arp_ip_dst(skb, 0);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_entry_add(bat_priv, &ip_src, BATADV_DAT_IPV4, hw_src, vid);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
+ dat_entry = batadv_dat_entry_hash_find(bat_priv, &ip_dst,
+ BATADV_DAT_IPV4, vid);
if (dat_entry) {
/* If the ARP request is destined for a local client the local
* client will answer itself. DAT would only generate a
@@ -962,7 +1052,8 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
ret = true;
} else {
/* Send the request to the DHT */
- ret = batadv_dat_send_data(bat_priv, skb, ip_dst,
+ ret = batadv_dat_send_data(bat_priv, skb, &ip_dst,
+ BATADV_DAT_IPV4,
BATADV_P_DAT_DHT_GET);
}
out:
@@ -1008,9 +1099,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
batadv_dbg_arp(bat_priv, skb, type, hdr_size,
"Parsing incoming ARP REQUEST");
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_entry_add(bat_priv, &ip_src, BATADV_DAT_IPV4, hw_src, vid);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
+ dat_entry = batadv_dat_entry_hash_find(bat_priv, &ip_dst,
+ BATADV_DAT_IPV4, vid);
if (!dat_entry)
goto out;
@@ -1074,14 +1166,16 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
hw_dst = batadv_arp_hw_dst(skb, hdr_size);
ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ batadv_dat_entry_add(bat_priv, &ip_src, BATADV_DAT_IPV4, hw_src, vid);
+ batadv_dat_entry_add(bat_priv, &ip_dst, BATADV_DAT_IPV4, hw_dst, vid);
/* Send the ARP reply to the candidates for both the IP addresses that
* the node obtained from the ARP reply
*/
- batadv_dat_send_data(bat_priv, skb, ip_src, BATADV_P_DAT_DHT_PUT);
- batadv_dat_send_data(bat_priv, skb, ip_dst, BATADV_P_DAT_DHT_PUT);
+ batadv_dat_send_data(bat_priv, skb, &ip_src, BATADV_DAT_IPV4,
+ BATADV_P_DAT_DHT_PUT);
+ batadv_dat_send_data(bat_priv, skb, &ip_dst, BATADV_DAT_IPV4,
+ BATADV_P_DAT_DHT_PUT);
}
/**
* batadv_dat_snoop_incoming_arp_reply - snoop the ARP reply and fill the local
@@ -1119,8 +1213,8 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
/* Update our internal cache with both the IP addresses the node got
* within the ARP reply
*/
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ batadv_dat_entry_add(bat_priv, &ip_src, BATADV_DAT_IPV4, hw_src, vid);
+ batadv_dat_entry_add(bat_priv, &ip_dst, BATADV_DAT_IPV4, hw_dst, vid);
/* if this REPLY is directed to a client of mine, let's deliver the
* packet to the interface
@@ -1167,7 +1261,8 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
goto out;
ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
+ dat_entry = batadv_dat_entry_hash_find(bat_priv, &ip_dst,
+ BATADV_DAT_IPV4, vid);
/* check if the node already got this entry */
if (!dat_entry) {
batadv_dbg(BATADV_DBG_DAT, bat_priv,
diff --git a/distributed-arp-table.h b/distributed-arp-table.h
index 60d853b..557bab9 100644
--- a/distributed-arp-table.h
+++ b/distributed-arp-table.h
@@ -28,6 +28,7 @@
#include <linux/if_arp.h>
#define BATADV_DAT_ADDR_MAX ((batadv_dat_addr_t)~(batadv_dat_addr_t)0)
+#define BATADV_DAT_DATA_MAX_LEN 16
void batadv_dat_status_update(struct net_device *net_dev);
bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
diff --git a/types.h b/types.h
index 20a1bef..69c187e 100644
--- a/types.h
+++ b/types.h
@@ -931,7 +931,8 @@ struct batadv_algo_ops {
/**
* struct batadv_dat_entry - it is a single entry of batman-adv ARP backend. It
* is used to stored ARP entries needed for the global DAT cache
- * @ip: the IPv4 corresponding to this DAT/ARP entry
+ * @data: the data corresponding to this DAT entry
+ * @type: the type corresponding to this DAT entry
* @mac_addr: the MAC address associated to the stored IPv4
* @vid: the vlan ID associated to this entry
* @last_update: time in jiffies when this entry was refreshed last time
@@ -940,7 +941,8 @@ struct batadv_algo_ops {
* @rcu: struct used for freeing in an RCU-safe manner
*/
struct batadv_dat_entry {
- __be32 ip;
+ void *data;
+ uint8_t type;
uint8_t mac_addr[ETH_ALEN];
unsigned short vid;
unsigned long last_update;
@@ -950,6 +952,24 @@ struct batadv_dat_entry {
};
/**
+ * batadv_dat_types - types used in batadv_dat_entry for IP
+ * @BATADV_DAT_IPv4: IPv4 address type
+ */
+enum batadv_dat_types {
+ BATADV_DAT_IPV4 = 0,
+};
+
+/**
+ * batadv_dat_type_info - info needed for a DAT type data
+ * @size: the size of the type data
+ * @str_fmt: string format used by the data
+ */
+struct batadv_dat_type_info {
+ size_t size;
+ char *str_fmt;
+};
+
+/**
* struct batadv_dat_candidate - candidate destination for DAT operations
* @type: the type of the selected candidate. It can one of the following:
* - BATADV_DAT_CANDIDATE_NOT_FOUND
--
1.7.10.4
Scenario:
I have recently moved 13 nodes previously using wds to batman-adv.
One problem that i am encountering is the gateway selection and its
actually defectiveness.
This problem has be seen when the client nodes are set on class 20.
The node clients in fact select the gateways that advertise better link
quality usually above 200 but at the same time some clients end up
connecting to a gateway that is either too slow or unusable either due
to routing or other factors such as distance and even clear visibility.
In one case the node connects to something that defies logic.
I thought about ways to work around this and came up with an idea that
may help which means the creation of 2 new classes.
- Preferred gateway fall-back
- Preferred fixed gateway
For Preferred gateway fall-back:
consider the gateway's advertised quality towards the gateway and stick
with the selection until the gateway disappears returning to it soon as
it returns regardless of any other data.
- Preferred fixed gateway
Manual gateway selection by the node owner or admin. (wds type)
If these classes cannot be created; maybe a plugin of some sort could
be. could be called "gordon".
I understand that this idea may sound useless the same way blocking
originators may be for someone but in some scenarios just like blocking
originators it look to me very valid.
My current problem is that the link quality seems to go up and down like
a roller coaster in a specific order which causes the clients to switch
constantly sometimes many times per hour.
While this does not seem to be an issue for most client nodes; for 2 of
them it means no internet access at all.
The solution for now seems to be having these 2 nodes forced to use 1
specific gateway.
I am quite open to any ideas that may help resolve this issue that has
been casing some "uninformed people" to become headaches.
--
Redes wireless
http://wirelesspt.net
Hi,
at the battlemesh we had plenty of time to discuss and test the tvlv
patchset. Therefore, a number of changes/fixes found their way into
v2 touching the tvlv API, network coding, unicast sending and gateway
announcements.
This looks like the final version which is going to be merged unless
objections are raised soon-ish.
Cheers,
Marek
discussed in IRC, i'am searched for a better way to
load-balance a batman network. not the whole shaping/splashing
should run on one (central) node, so we needed something to stick it
to the node/AP which the user is connected to. than we have also
the ability to show a good page when the network is b0rken.
short overview:
NODE-1 (master/gateway)
ipv4: 192.168.1.1/16
dhcp: 192.168.1.x / gateway: 192.168.0.1
gateway: e.g. pppoe
NODE-2
ipv4: 192.168.2.1/16
dhcp: 192.168.2.x / gateway: 192.168.0.1
gateway: 192.168.1.1
NODE-3
ipv4: 192.168.3.1/16
dhcp: 192.168.3.x / gateway: 192.168.0.1
gateway: 192.168.1.1
the trick is, that every node offers DHCP which
does not interfere with other nodes AND offers a
gateway which is always the same: 192.168.0.1
if a user roams he simply moves on layer 1/2 and
its further working ok. important: the MAC of the
gateway should not change otherwise it's not working
for some seconds till the ARP times out. this can
be circumvented via kmod-macvlan:
ip link add link br-mybridge gateway0 address '02:00:c0:ca:c0:1a' type macvlan
ip address add 192.168.0.1/16 dev gateway0
ip link set dev gateway0 up
then the IP 192.168.0.1 is always reachable with the same MAC.
thats it. we can use the "normal" iptables/tc stuff like in
olsrd-networks...
giving out such dhcp-leases needs a fix to /etc/init.d/dhcp
which is available soon on OpenWrt mailinglist.
bye, bastian
PS:
thanks for the discussion and help, escpecially to T_X, ordex and marec
While I'm still in Europe I've observed that the network in Quintana has
started performing very poorly today. It was working perfectly fine
until yesterday.
The logs on every router have started showing entries like these:
Oct 13 18:09:43 frigorifico kern.warn kernel: [12018.150000] br-lan:
received packet on bat0 with own address as source address
Oct 13 18:09:45 frigorifico kern.warn kernel: [12020.040000] br-lan:
received packet on bat0 with own address as source address
Oct 13 18:09:45 frigorifico kern.warn kernel: [12020.040000] br-lan:
received packet on bat0 with own address as source address
Oct 13 18:09:45 frigorifico kern.warn kernel: [12020.550000] br-lan:
received packet on bat0 with own address as source address
Oct 13 18:09:45 frigorifico kern.warn kernel: [12020.550000] br-lan:
received packet on bat0 with own address as source address
Oct 13 18:09:45 frigorifico kern.warn kernel: [12020.570000] br-lan:
received packet on bat0 with own address as source address
Oct 13 18:09:45 frigorifico kern.warn kernel: [12020.580000] br-lan:
received packet on bat0 with own address as source address
Oct 13 18:09:46 frigorifico kern.warn kernel: [12021.040000] br-lan:
received packet on bat0 with own address as source address
As you can see there are many per second.
I've pasted a bit of batctl ll batman; batctl log here:
http://pastebin.com/HX1LBPK4
...it's only showing the "originator packet from myself" lines and one
line before. (the sample is less than 5 secs of logs)
Every node I checked is showing the same.
Last time this happened it was due to a router that had been affected by
a nearby lightning bolt. The switch went crazy.
It took a while to detect it and the network was 15 nodes big. Now it's
40 and we are quite far away :)
If anyone has an idea of how to better test where the problem is
originated, I'll be glad to hear it. Also if any batman devel wishes to
log in to the net to check first hand, just let me know.
Cheers!
Nico
PS: batman version is 2012.4
Provide a lua script that uses alfred to propagate and collect all interface
mac + names, then generate a /tmp/bat-hosts file.
If there's already a (probably hand-made) /etc/bat-hosts it won't overwrite it
but if there's none, it will symlink /etc/bat-hosts -> /tmp/bat-hosts
Signed-off-by: Gui Iribarren <gui(a)altermundi.net>
Thanks-to: Joshua Head <joshua.head(a)outlook.com>
---
alfred/Makefile | 2 +
alfred/files/bat-hosts.lua | 107 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 109 insertions(+)
create mode 100644 alfred/files/bat-hosts.lua
diff --git a/alfred/Makefile b/alfred/Makefile
index db9c71f..7027192 100644
--- a/alfred/Makefile
+++ b/alfred/Makefile
@@ -74,6 +74,8 @@ define Package/alfred/install
$(INSTALL_BIN) ./files/alfred.init $(1)/etc/init.d/alfred
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/alfred.config $(1)/etc/config/alfred
+ $(INSTALL_DIR) $(1)/etc/alfred
+ $(INSTALL_BIN) ./files/bat-hosts.lua $(1)/etc/alfred/bat-hosts.lua
endef
$(eval $(call BuildPackage,alfred))
diff --git a/alfred/files/bat-hosts.lua b/alfred/files/bat-hosts.lua
new file mode 100644
index 0000000..19f2cad
--- /dev/null
+++ b/alfred/files/bat-hosts.lua
@@ -0,0 +1,107 @@
+#!/usr/bin/lua
+
+local type_id = 64 -- bat-hosts
+
+function get_hostname()
+ local hostfile = io.open("/proc/sys/kernel/hostname", "r")
+ local ret_string = hostfile:read("*a")
+ ret_string = string.gsub(ret_string, "\n", "")
+ hostfile:close()
+ return ret_string
+end
+
+function get_interfaces_names()
+ local ret = {}
+
+ for name in io.popen("ls -1 /sys/class/net/"):lines() do
+ table.insert(ret, name)
+ end
+
+ return ret
+end
+
+function get_interface_address(name)
+ local addressfile = io.open("/sys/class/net/"..name.."/address", "r")
+ local ret_string = addressfile:read("*a")
+ ret_string = string.gsub(ret_string, "\n", "")
+ addressfile:close()
+ return ret_string
+end
+
+
+local function generate_bat_hosts()
+-- get hostname and interface macs/names
+-- then return a table containing valid bat-hosts lines
+ local n, i
+ local ifaces, ret = {}, {}
+
+ local hostname = get_hostname()
+
+ for n, i in ipairs(get_interfaces_names()) do
+ local address = get_interface_address(i)
+ ifaces[address] = i
+ end
+
+ for mac, iname in pairs(ifaces) do
+ if mac:match("^%x%x:%x%x:%x%x:%x%x:%x%x:%x%x$") and not mac:match("00:00:00:00:00:00") then
+ table.insert(ret, mac.." "..hostname.."_"..iname.."\n")
+ end
+ end
+
+ return ret
+end
+
+local function publish_bat_hosts()
+-- pass a raw chunk of data to alfred
+ local fd = io.popen("alfred -s " .. type_id, "w")
+ if fd then
+ local ret = generate_bat_hosts()
+ if ret then
+ fd:write(table.concat(ret))
+ end
+ fd:close()
+ end
+end
+
+local function receive_bat_hosts()
+-- read raw chunks from alfred, convert them to a nested table and call write_bat_hosts
+ local fd = io.popen("alfred -r " .. type_id)
+ --[[ this command returns something like
+ { "54:e6:fc:b9:cb:37", "00:11:22:33:44:55 ham_wlan0\x0a00:22:33:22:33:22 ham_eth0\x0a" },
+ { "90:f6:52:bb:ec:57", "00:22:33:22:33:23 spam\x0a" },
+ ]]--
+
+ if fd then
+ local output = fd:read("*a")
+ if output then
+ assert(loadstring("rows = {" .. output .. "}"))()
+ write_bat_hosts(rows)
+ end
+ fd:close()
+ end
+end
+
+local function write_bat_hosts(rows)
+ local content = { "### File generated by alfred-bat-hosts\n" }
+
+ -- merge the chunks from all nodes, de-escaping newlines
+ for _, row in ipairs(rows) do
+ local node, value = unpack(row)
+ table.insert(content, "# Node ".. node .. "\n")
+ table.insert(content, value:gsub("\x0a", "\n") .. "\n")
+ end
+
+ -- write parsed content down to disk
+ local fd = io.open("/tmp/bat-hosts", "w")
+ if fd then
+ fd:write(table.concat(content))
+ fd:close()
+ end
+
+ -- try to make a symlink in /etc pointing to /tmp,
+ -- if it exists, ln will do nothing.
+ os.execute("ln -ns /tmp/bat-hosts /etc/bat-hosts 2>/dev/null")
+end
+
+publish_bat_hosts()
+receive_bat_hosts()
--
1.7.10.4