Merge branch 'batman-adv/next' of git://git.open-mesh.org/linux-merge
This commit is contained in:
commit
3f9aed7c7d
|
@ -223,6 +223,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
|
||||||
orig_node->bat_priv = bat_priv;
|
orig_node->bat_priv = bat_priv;
|
||||||
memcpy(orig_node->orig, addr, ETH_ALEN);
|
memcpy(orig_node->orig, addr, ETH_ALEN);
|
||||||
orig_node->router = NULL;
|
orig_node->router = NULL;
|
||||||
|
orig_node->tt_crc = 0;
|
||||||
|
atomic_set(&orig_node->last_ttvn, 0);
|
||||||
orig_node->tt_buff = NULL;
|
orig_node->tt_buff = NULL;
|
||||||
orig_node->tt_buff_len = 0;
|
orig_node->tt_buff_len = 0;
|
||||||
atomic_set(&orig_node->tt_size, 0);
|
atomic_set(&orig_node->tt_size, 0);
|
||||||
|
|
|
@ -84,7 +84,9 @@ enum tt_query_flags {
|
||||||
enum tt_client_flags {
|
enum tt_client_flags {
|
||||||
TT_CLIENT_DEL = 1 << 0,
|
TT_CLIENT_DEL = 1 << 0,
|
||||||
TT_CLIENT_ROAM = 1 << 1,
|
TT_CLIENT_ROAM = 1 << 1,
|
||||||
TT_CLIENT_NOPURGE = 1 << 8
|
TT_CLIENT_NOPURGE = 1 << 8,
|
||||||
|
TT_CLIENT_NEW = 1 << 9,
|
||||||
|
TT_CLIENT_PENDING = 1 << 10
|
||||||
};
|
};
|
||||||
|
|
||||||
struct batman_packet {
|
struct batman_packet {
|
||||||
|
|
|
@ -91,6 +91,18 @@ static void update_transtable(struct bat_priv *bat_priv,
|
||||||
* to recompute it to spot any possible inconsistency
|
* to recompute it to spot any possible inconsistency
|
||||||
* in the global table */
|
* in the global table */
|
||||||
orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
|
orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
|
||||||
|
|
||||||
|
/* The ttvn alone is not enough to guarantee consistency
|
||||||
|
* because a single value could repesent different states
|
||||||
|
* (due to the wrap around). Thus a node has to check whether
|
||||||
|
* the resulting table (after applying the changes) is still
|
||||||
|
* consistent or not. E.g. a node could disconnect while its
|
||||||
|
* ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
|
||||||
|
* checking the CRC value is mandatory to detect the
|
||||||
|
* inconsistency */
|
||||||
|
if (orig_node->tt_crc != tt_crc)
|
||||||
|
goto request_table;
|
||||||
|
|
||||||
/* Roaming phase is over: tables are in sync again. I can
|
/* Roaming phase is over: tables are in sync again. I can
|
||||||
* unset the flag */
|
* unset the flag */
|
||||||
orig_node->tt_poss_change = false;
|
orig_node->tt_poss_change = false;
|
||||||
|
|
|
@ -309,10 +309,8 @@ void schedule_own_packet(struct hard_iface *hard_iface)
|
||||||
if (hard_iface == primary_if) {
|
if (hard_iface == primary_if) {
|
||||||
/* if at least one change happened */
|
/* if at least one change happened */
|
||||||
if (atomic_read(&bat_priv->tt_local_changes) > 0) {
|
if (atomic_read(&bat_priv->tt_local_changes) > 0) {
|
||||||
|
tt_commit_changes(bat_priv);
|
||||||
prepare_packet_buffer(bat_priv, hard_iface);
|
prepare_packet_buffer(bat_priv, hard_iface);
|
||||||
/* Increment the TTVN only once per OGM interval */
|
|
||||||
atomic_inc(&bat_priv->ttvn);
|
|
||||||
bat_priv->tt_poss_change = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the changes have been sent enough times */
|
/* if the changes have been sent enough times */
|
||||||
|
|
|
@ -215,11 +215,14 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
|
||||||
|
|
||||||
tt_local_event(bat_priv, addr, tt_local_entry->flags);
|
tt_local_event(bat_priv, addr, tt_local_entry->flags);
|
||||||
|
|
||||||
|
/* The local entry has to be marked as NEW to avoid to send it in
|
||||||
|
* a full table response going out before the next ttvn increment
|
||||||
|
* (consistency check) */
|
||||||
|
tt_local_entry->flags |= TT_CLIENT_NEW;
|
||||||
|
|
||||||
hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
|
hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
|
||||||
tt_local_entry, &tt_local_entry->hash_entry);
|
tt_local_entry, &tt_local_entry->hash_entry);
|
||||||
|
|
||||||
atomic_inc(&bat_priv->num_local_tt);
|
|
||||||
|
|
||||||
/* remove address from global hash if present */
|
/* remove address from global hash if present */
|
||||||
tt_global_entry = tt_global_hash_find(bat_priv, addr);
|
tt_global_entry = tt_global_hash_find(bat_priv, addr);
|
||||||
|
|
||||||
|
@ -227,8 +230,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
|
||||||
if (tt_global_entry) {
|
if (tt_global_entry) {
|
||||||
/* This node is probably going to update its tt table */
|
/* This node is probably going to update its tt table */
|
||||||
tt_global_entry->orig_node->tt_poss_change = true;
|
tt_global_entry->orig_node->tt_poss_change = true;
|
||||||
_tt_global_del(bat_priv, tt_global_entry,
|
/* The global entry has to be marked as PENDING and has to be
|
||||||
"local tt received");
|
* kept for consistency purpose */
|
||||||
|
tt_global_entry->flags |= TT_CLIENT_PENDING;
|
||||||
send_roam_adv(bat_priv, tt_global_entry->addr,
|
send_roam_adv(bat_priv, tt_global_entry->addr,
|
||||||
tt_global_entry->orig_node);
|
tt_global_entry->orig_node);
|
||||||
}
|
}
|
||||||
|
@ -358,19 +362,17 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tt_local_del(struct bat_priv *bat_priv,
|
static void tt_local_set_pending(struct bat_priv *bat_priv,
|
||||||
struct tt_local_entry *tt_local_entry,
|
struct tt_local_entry *tt_local_entry,
|
||||||
const char *message)
|
uint16_t flags)
|
||||||
{
|
{
|
||||||
bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n",
|
tt_local_event(bat_priv, tt_local_entry->addr,
|
||||||
tt_local_entry->addr, message);
|
tt_local_entry->flags | flags);
|
||||||
|
|
||||||
atomic_dec(&bat_priv->num_local_tt);
|
/* The local client has to be merked as "pending to be removed" but has
|
||||||
|
* to be kept in the table in order to send it in an full tables
|
||||||
hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
|
* response issued before the net ttvn increment (consistency check) */
|
||||||
tt_local_entry->addr);
|
tt_local_entry->flags |= TT_CLIENT_PENDING;
|
||||||
|
|
||||||
tt_local_entry_free_ref(tt_local_entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
|
void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
|
||||||
|
@ -379,14 +381,14 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
|
||||||
struct tt_local_entry *tt_local_entry = NULL;
|
struct tt_local_entry *tt_local_entry = NULL;
|
||||||
|
|
||||||
tt_local_entry = tt_local_hash_find(bat_priv, addr);
|
tt_local_entry = tt_local_hash_find(bat_priv, addr);
|
||||||
|
|
||||||
if (!tt_local_entry)
|
if (!tt_local_entry)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
tt_local_event(bat_priv, tt_local_entry->addr,
|
tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
|
||||||
tt_local_entry->flags | TT_CLIENT_DEL |
|
(roaming ? TT_CLIENT_ROAM : NO_FLAGS));
|
||||||
(roaming ? TT_CLIENT_ROAM : NO_FLAGS));
|
|
||||||
tt_local_del(bat_priv, tt_local_entry, message);
|
bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
|
||||||
|
"%s\n", tt_local_entry->addr, message);
|
||||||
out:
|
out:
|
||||||
if (tt_local_entry)
|
if (tt_local_entry)
|
||||||
tt_local_entry_free_ref(tt_local_entry);
|
tt_local_entry_free_ref(tt_local_entry);
|
||||||
|
@ -411,18 +413,19 @@ static void tt_local_purge(struct bat_priv *bat_priv)
|
||||||
if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
|
if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* entry already marked for deletion */
|
||||||
|
if (tt_local_entry->flags & TT_CLIENT_PENDING)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!is_out_of_time(tt_local_entry->last_seen,
|
if (!is_out_of_time(tt_local_entry->last_seen,
|
||||||
TT_LOCAL_TIMEOUT * 1000))
|
TT_LOCAL_TIMEOUT * 1000))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tt_local_event(bat_priv, tt_local_entry->addr,
|
tt_local_set_pending(bat_priv, tt_local_entry,
|
||||||
tt_local_entry->flags | TT_CLIENT_DEL);
|
TT_CLIENT_DEL);
|
||||||
atomic_dec(&bat_priv->num_local_tt);
|
bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
|
||||||
bat_dbg(DBG_TT, bat_priv, "Deleting local "
|
"pending to be removed: timed out\n",
|
||||||
"tt entry (%pM): timed out\n",
|
|
||||||
tt_local_entry->addr);
|
tt_local_entry->addr);
|
||||||
hlist_del_rcu(node);
|
|
||||||
tt_local_entry_free_ref(tt_local_entry);
|
|
||||||
}
|
}
|
||||||
spin_unlock_bh(list_lock);
|
spin_unlock_bh(list_lock);
|
||||||
}
|
}
|
||||||
|
@ -785,6 +788,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
|
||||||
if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
|
if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
|
||||||
goto free_tt;
|
goto free_tt;
|
||||||
|
|
||||||
|
/* A global client marked as PENDING has already moved from that
|
||||||
|
* originator */
|
||||||
|
if (tt_global_entry->flags & TT_CLIENT_PENDING)
|
||||||
|
goto free_tt;
|
||||||
|
|
||||||
orig_node = tt_global_entry->orig_node;
|
orig_node = tt_global_entry->orig_node;
|
||||||
|
|
||||||
free_tt:
|
free_tt:
|
||||||
|
@ -846,6 +854,10 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv)
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
hlist_for_each_entry_rcu(tt_local_entry, node,
|
hlist_for_each_entry_rcu(tt_local_entry, node,
|
||||||
head, hash_entry) {
|
head, hash_entry) {
|
||||||
|
/* not yet committed clients have not to be taken into
|
||||||
|
* account while computing the CRC */
|
||||||
|
if (tt_local_entry->flags & TT_CLIENT_NEW)
|
||||||
|
continue;
|
||||||
total_one = 0;
|
total_one = 0;
|
||||||
for (j = 0; j < ETH_ALEN; j++)
|
for (j = 0; j < ETH_ALEN; j++)
|
||||||
total_one = crc16_byte(total_one,
|
total_one = crc16_byte(total_one,
|
||||||
|
@ -935,6 +947,16 @@ unlock:
|
||||||
return tt_req_node;
|
return tt_req_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* data_ptr is useless here, but has to be kept to respect the prototype */
|
||||||
|
static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
|
||||||
|
{
|
||||||
|
const struct tt_local_entry *tt_local_entry = entry_ptr;
|
||||||
|
|
||||||
|
if (tt_local_entry->flags & TT_CLIENT_NEW)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
|
static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
|
||||||
{
|
{
|
||||||
const struct tt_global_entry *tt_global_entry = entry_ptr;
|
const struct tt_global_entry *tt_global_entry = entry_ptr;
|
||||||
|
@ -1275,7 +1297,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,
|
||||||
|
|
||||||
skb = tt_response_fill_table(tt_len, ttvn,
|
skb = tt_response_fill_table(tt_len, ttvn,
|
||||||
bat_priv->tt_local_hash,
|
bat_priv->tt_local_hash,
|
||||||
primary_if, NULL, NULL);
|
primary_if, tt_local_valid_entry,
|
||||||
|
NULL);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -1400,6 +1423,10 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
|
||||||
tt_local_entry = tt_local_hash_find(bat_priv, addr);
|
tt_local_entry = tt_local_hash_find(bat_priv, addr);
|
||||||
if (!tt_local_entry)
|
if (!tt_local_entry)
|
||||||
goto out;
|
goto out;
|
||||||
|
/* Check if the client has been logically deleted (but is kept for
|
||||||
|
* consistency purpose) */
|
||||||
|
if (tt_local_entry->flags & TT_CLIENT_PENDING)
|
||||||
|
goto out;
|
||||||
ret = true;
|
ret = true;
|
||||||
out:
|
out:
|
||||||
if (tt_local_entry)
|
if (tt_local_entry)
|
||||||
|
@ -1620,3 +1647,76 @@ void tt_free(struct bat_priv *bat_priv)
|
||||||
|
|
||||||
kfree(bat_priv->tt_buff);
|
kfree(bat_priv->tt_buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function will reset the specified flags from all the entries in
|
||||||
|
* the given hash table and will increment num_local_tt for each involved
|
||||||
|
* entry */
|
||||||
|
static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct hashtable_t *hash = bat_priv->tt_local_hash;
|
||||||
|
struct hlist_head *head;
|
||||||
|
struct hlist_node *node;
|
||||||
|
struct tt_local_entry *tt_local_entry;
|
||||||
|
|
||||||
|
if (!hash)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < hash->size; i++) {
|
||||||
|
head = &hash->table[i];
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
hlist_for_each_entry_rcu(tt_local_entry, node,
|
||||||
|
head, hash_entry) {
|
||||||
|
tt_local_entry->flags &= ~flags;
|
||||||
|
atomic_inc(&bat_priv->num_local_tt);
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
|
||||||
|
static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
|
||||||
|
{
|
||||||
|
struct hashtable_t *hash = bat_priv->tt_local_hash;
|
||||||
|
struct tt_local_entry *tt_local_entry;
|
||||||
|
struct hlist_node *node, *node_tmp;
|
||||||
|
struct hlist_head *head;
|
||||||
|
spinlock_t *list_lock; /* protects write access to the hash lists */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!hash)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < hash->size; i++) {
|
||||||
|
head = &hash->table[i];
|
||||||
|
list_lock = &hash->list_locks[i];
|
||||||
|
|
||||||
|
spin_lock_bh(list_lock);
|
||||||
|
hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
|
||||||
|
head, hash_entry) {
|
||||||
|
if (!(tt_local_entry->flags & TT_CLIENT_PENDING))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
|
||||||
|
"(%pM): pending\n", tt_local_entry->addr);
|
||||||
|
|
||||||
|
atomic_dec(&bat_priv->num_local_tt);
|
||||||
|
hlist_del_rcu(node);
|
||||||
|
tt_local_entry_free_ref(tt_local_entry);
|
||||||
|
}
|
||||||
|
spin_unlock_bh(list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void tt_commit_changes(struct bat_priv *bat_priv)
|
||||||
|
{
|
||||||
|
tt_local_reset_flags(bat_priv, TT_CLIENT_NEW);
|
||||||
|
tt_local_purge_pending_clients(bat_priv);
|
||||||
|
|
||||||
|
/* Increment the TTVN only once per OGM interval */
|
||||||
|
atomic_inc(&bat_priv->ttvn);
|
||||||
|
bat_priv->tt_poss_change = false;
|
||||||
|
}
|
||||||
|
|
|
@ -61,5 +61,6 @@ void handle_tt_response(struct bat_priv *bat_priv,
|
||||||
struct tt_query_packet *tt_response);
|
struct tt_query_packet *tt_response);
|
||||||
void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
|
void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
|
||||||
struct orig_node *orig_node);
|
struct orig_node *orig_node);
|
||||||
|
void tt_commit_changes(struct bat_priv *bat_priv);
|
||||||
|
|
||||||
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
|
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
|
||||||
|
|
Loading…
Reference in New Issue