diff options
author | Antonio Quartulli <ordex@autistici.org> | 2011-07-06 19:40:58 -0400 |
---|---|---|
committer | Marek Lindner <lindner_marek@yahoo.de> | 2011-07-07 12:49:26 -0400 |
commit | 058d0e26989e3da2fa031f551235f6ff1e0bc27c (patch) | |
tree | f39ce9771166b9a110a38c65621eb2128c152068 /net/batman-adv | |
parent | c8c991bf2076d711f14ff9063db306fd522ddcd4 (diff) |
batman-adv: keep local table consistency for further TT_RESPONSE
To keep transtable consistency among all the nodes, an originator must
not send not yet announced clients within a full table TT_RESPONSE.
Instead, deleted client have to be kept in the table in order to be sent
within an immediate TT_RESPONSE. In this way all the nodes in the
network will always provide the same response for the same request.
All the modification are committed at the next ttvn increment event.
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Diffstat (limited to 'net/batman-adv')
-rw-r--r-- | net/batman-adv/packet.h | 4 | ||||
-rw-r--r-- | net/batman-adv/send.c | 4 | ||||
-rw-r--r-- | net/batman-adv/translation-table.c | 146 | ||||
-rw-r--r-- | net/batman-adv/translation-table.h | 1 |
4 files changed, 125 insertions, 30 deletions
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 590e4a66089f..b76b4be10b92 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h | |||
@@ -84,7 +84,9 @@ enum tt_query_flags { | |||
84 | enum tt_client_flags { | 84 | enum tt_client_flags { |
85 | TT_CLIENT_DEL = 1 << 0, | 85 | TT_CLIENT_DEL = 1 << 0, |
86 | TT_CLIENT_ROAM = 1 << 1, | 86 | TT_CLIENT_ROAM = 1 << 1, |
87 | TT_CLIENT_NOPURGE = 1 << 8 | 87 | TT_CLIENT_NOPURGE = 1 << 8, |
88 | TT_CLIENT_NEW = 1 << 9, | ||
89 | TT_CLIENT_PENDING = 1 << 10 | ||
88 | }; | 90 | }; |
89 | 91 | ||
90 | struct batman_packet { | 92 | struct batman_packet { |
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 4b8e11bc14fa..58d14472068c 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c | |||
@@ -309,10 +309,8 @@ void schedule_own_packet(struct hard_iface *hard_iface) | |||
309 | if (hard_iface == primary_if) { | 309 | if (hard_iface == primary_if) { |
310 | /* if at least one change happened */ | 310 | /* if at least one change happened */ |
311 | if (atomic_read(&bat_priv->tt_local_changes) > 0) { | 311 | if (atomic_read(&bat_priv->tt_local_changes) > 0) { |
312 | tt_commit_changes(bat_priv); | ||
312 | prepare_packet_buffer(bat_priv, hard_iface); | 313 | prepare_packet_buffer(bat_priv, hard_iface); |
313 | /* Increment the TTVN only once per OGM interval */ | ||
314 | atomic_inc(&bat_priv->ttvn); | ||
315 | bat_priv->tt_poss_change = false; | ||
316 | } | 314 | } |
317 | 315 | ||
318 | /* if the changes have been sent enough times */ | 316 | /* if the changes have been sent enough times */ |
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 06d361d4ac4b..7cc67c0f4915 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -215,11 +215,14 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) | |||
215 | 215 | ||
216 | tt_local_event(bat_priv, addr, tt_local_entry->flags); | 216 | tt_local_event(bat_priv, addr, tt_local_entry->flags); |
217 | 217 | ||
218 | /* The local entry has to be marked as NEW to avoid to send it in | ||
219 | * a full table response going out before the next ttvn increment | ||
220 | * (consistency check) */ | ||
221 | tt_local_entry->flags |= TT_CLIENT_NEW; | ||
222 | |||
218 | hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, | 223 | hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, |
219 | tt_local_entry, &tt_local_entry->hash_entry); | 224 | tt_local_entry, &tt_local_entry->hash_entry); |
220 | 225 | ||
221 | atomic_inc(&bat_priv->num_local_tt); | ||
222 | |||
223 | /* remove address from global hash if present */ | 226 | /* remove address from global hash if present */ |
224 | tt_global_entry = tt_global_hash_find(bat_priv, addr); | 227 | tt_global_entry = tt_global_hash_find(bat_priv, addr); |
225 | 228 | ||
@@ -358,19 +361,17 @@ out: | |||
358 | return ret; | 361 | return ret; |
359 | } | 362 | } |
360 | 363 | ||
361 | static void tt_local_del(struct bat_priv *bat_priv, | 364 | static void tt_local_set_pending(struct bat_priv *bat_priv, |
362 | struct tt_local_entry *tt_local_entry, | 365 | struct tt_local_entry *tt_local_entry, |
363 | const char *message) | 366 | uint16_t flags) |
364 | { | 367 | { |
365 | bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n", | 368 | tt_local_event(bat_priv, tt_local_entry->addr, |
366 | tt_local_entry->addr, message); | 369 | tt_local_entry->flags | flags); |
367 | |||
368 | atomic_dec(&bat_priv->num_local_tt); | ||
369 | |||
370 | hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig, | ||
371 | tt_local_entry->addr); | ||
372 | 370 | ||
373 | tt_local_entry_free_ref(tt_local_entry); | 371 | /* The local client has to be merked as "pending to be removed" but has |
372 | * to be kept in the table in order to send it in an full tables | ||
373 | * response issued before the net ttvn increment (consistency check) */ | ||
374 | tt_local_entry->flags |= TT_CLIENT_PENDING; | ||
374 | } | 375 | } |
375 | 376 | ||
376 | void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, | 377 | void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, |
@@ -379,14 +380,14 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, | |||
379 | struct tt_local_entry *tt_local_entry = NULL; | 380 | struct tt_local_entry *tt_local_entry = NULL; |
380 | 381 | ||
381 | tt_local_entry = tt_local_hash_find(bat_priv, addr); | 382 | tt_local_entry = tt_local_hash_find(bat_priv, addr); |
382 | |||
383 | if (!tt_local_entry) | 383 | if (!tt_local_entry) |
384 | goto out; | 384 | goto out; |
385 | 385 | ||
386 | tt_local_event(bat_priv, tt_local_entry->addr, | 386 | tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | |
387 | tt_local_entry->flags | TT_CLIENT_DEL | | 387 | (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); |
388 | (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); | 388 | |
389 | tt_local_del(bat_priv, tt_local_entry, message); | 389 | bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " |
390 | "%s\n", tt_local_entry->addr, message); | ||
390 | out: | 391 | out: |
391 | if (tt_local_entry) | 392 | if (tt_local_entry) |
392 | tt_local_entry_free_ref(tt_local_entry); | 393 | tt_local_entry_free_ref(tt_local_entry); |
@@ -411,18 +412,19 @@ static void tt_local_purge(struct bat_priv *bat_priv) | |||
411 | if (tt_local_entry->flags & TT_CLIENT_NOPURGE) | 412 | if (tt_local_entry->flags & TT_CLIENT_NOPURGE) |
412 | continue; | 413 | continue; |
413 | 414 | ||
415 | /* entry already marked for deletion */ | ||
416 | if (tt_local_entry->flags & TT_CLIENT_PENDING) | ||
417 | continue; | ||
418 | |||
414 | if (!is_out_of_time(tt_local_entry->last_seen, | 419 | if (!is_out_of_time(tt_local_entry->last_seen, |
415 | TT_LOCAL_TIMEOUT * 1000)) | 420 | TT_LOCAL_TIMEOUT * 1000)) |
416 | continue; | 421 | continue; |
417 | 422 | ||
418 | tt_local_event(bat_priv, tt_local_entry->addr, | 423 | tt_local_set_pending(bat_priv, tt_local_entry, |
419 | tt_local_entry->flags | TT_CLIENT_DEL); | 424 | TT_CLIENT_DEL); |
420 | atomic_dec(&bat_priv->num_local_tt); | 425 | bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) " |
421 | bat_dbg(DBG_TT, bat_priv, "Deleting local " | 426 | "pending to be removed: timed out\n", |
422 | "tt entry (%pM): timed out\n", | ||
423 | tt_local_entry->addr); | 427 | tt_local_entry->addr); |
424 | hlist_del_rcu(node); | ||
425 | tt_local_entry_free_ref(tt_local_entry); | ||
426 | } | 428 | } |
427 | spin_unlock_bh(list_lock); | 429 | spin_unlock_bh(list_lock); |
428 | } | 430 | } |
@@ -846,6 +848,10 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv) | |||
846 | rcu_read_lock(); | 848 | rcu_read_lock(); |
847 | hlist_for_each_entry_rcu(tt_local_entry, node, | 849 | hlist_for_each_entry_rcu(tt_local_entry, node, |
848 | head, hash_entry) { | 850 | head, hash_entry) { |
851 | /* not yet committed clients have not to be taken into | ||
852 | * account while computing the CRC */ | ||
853 | if (tt_local_entry->flags & TT_CLIENT_NEW) | ||
854 | continue; | ||
849 | total_one = 0; | 855 | total_one = 0; |
850 | for (j = 0; j < ETH_ALEN; j++) | 856 | for (j = 0; j < ETH_ALEN; j++) |
851 | total_one = crc16_byte(total_one, | 857 | total_one = crc16_byte(total_one, |
@@ -935,6 +941,16 @@ unlock: | |||
935 | return tt_req_node; | 941 | return tt_req_node; |
936 | } | 942 | } |
937 | 943 | ||
944 | /* data_ptr is useless here, but has to be kept to respect the prototype */ | ||
945 | static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr) | ||
946 | { | ||
947 | const struct tt_local_entry *tt_local_entry = entry_ptr; | ||
948 | |||
949 | if (tt_local_entry->flags & TT_CLIENT_NEW) | ||
950 | return 0; | ||
951 | return 1; | ||
952 | } | ||
953 | |||
938 | static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) | 954 | static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) |
939 | { | 955 | { |
940 | const struct tt_global_entry *tt_global_entry = entry_ptr; | 956 | const struct tt_global_entry *tt_global_entry = entry_ptr; |
@@ -1275,7 +1291,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv, | |||
1275 | 1291 | ||
1276 | skb = tt_response_fill_table(tt_len, ttvn, | 1292 | skb = tt_response_fill_table(tt_len, ttvn, |
1277 | bat_priv->tt_local_hash, | 1293 | bat_priv->tt_local_hash, |
1278 | primary_if, NULL, NULL); | 1294 | primary_if, tt_local_valid_entry, |
1295 | NULL); | ||
1279 | if (!skb) | 1296 | if (!skb) |
1280 | goto out; | 1297 | goto out; |
1281 | 1298 | ||
@@ -1400,6 +1417,10 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) | |||
1400 | tt_local_entry = tt_local_hash_find(bat_priv, addr); | 1417 | tt_local_entry = tt_local_hash_find(bat_priv, addr); |
1401 | if (!tt_local_entry) | 1418 | if (!tt_local_entry) |
1402 | goto out; | 1419 | goto out; |
1420 | /* Check if the client has been logically deleted (but is kept for | ||
1421 | * consistency purpose) */ | ||
1422 | if (tt_local_entry->flags & TT_CLIENT_PENDING) | ||
1423 | goto out; | ||
1403 | ret = true; | 1424 | ret = true; |
1404 | out: | 1425 | out: |
1405 | if (tt_local_entry) | 1426 | if (tt_local_entry) |
@@ -1620,3 +1641,76 @@ void tt_free(struct bat_priv *bat_priv) | |||
1620 | 1641 | ||
1621 | kfree(bat_priv->tt_buff); | 1642 | kfree(bat_priv->tt_buff); |
1622 | } | 1643 | } |
1644 | |||
1645 | /* This function will reset the specified flags from all the entries in | ||
1646 | * the given hash table and will increment num_local_tt for each involved | ||
1647 | * entry */ | ||
1648 | static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags) | ||
1649 | { | ||
1650 | int i; | ||
1651 | struct hashtable_t *hash = bat_priv->tt_local_hash; | ||
1652 | struct hlist_head *head; | ||
1653 | struct hlist_node *node; | ||
1654 | struct tt_local_entry *tt_local_entry; | ||
1655 | |||
1656 | if (!hash) | ||
1657 | return; | ||
1658 | |||
1659 | for (i = 0; i < hash->size; i++) { | ||
1660 | head = &hash->table[i]; | ||
1661 | |||
1662 | rcu_read_lock(); | ||
1663 | hlist_for_each_entry_rcu(tt_local_entry, node, | ||
1664 | head, hash_entry) { | ||
1665 | tt_local_entry->flags &= ~flags; | ||
1666 | atomic_inc(&bat_priv->num_local_tt); | ||
1667 | } | ||
1668 | rcu_read_unlock(); | ||
1669 | } | ||
1670 | |||
1671 | } | ||
1672 | |||
1673 | /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ | ||
1674 | static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) | ||
1675 | { | ||
1676 | struct hashtable_t *hash = bat_priv->tt_local_hash; | ||
1677 | struct tt_local_entry *tt_local_entry; | ||
1678 | struct hlist_node *node, *node_tmp; | ||
1679 | struct hlist_head *head; | ||
1680 | spinlock_t *list_lock; /* protects write access to the hash lists */ | ||
1681 | int i; | ||
1682 | |||
1683 | if (!hash) | ||
1684 | return; | ||
1685 | |||
1686 | for (i = 0; i < hash->size; i++) { | ||
1687 | head = &hash->table[i]; | ||
1688 | list_lock = &hash->list_locks[i]; | ||
1689 | |||
1690 | spin_lock_bh(list_lock); | ||
1691 | hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, | ||
1692 | head, hash_entry) { | ||
1693 | if (!(tt_local_entry->flags & TT_CLIENT_PENDING)) | ||
1694 | continue; | ||
1695 | |||
1696 | bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " | ||
1697 | "(%pM): pending\n", tt_local_entry->addr); | ||
1698 | |||
1699 | atomic_dec(&bat_priv->num_local_tt); | ||
1700 | hlist_del_rcu(node); | ||
1701 | tt_local_entry_free_ref(tt_local_entry); | ||
1702 | } | ||
1703 | spin_unlock_bh(list_lock); | ||
1704 | } | ||
1705 | |||
1706 | } | ||
1707 | |||
1708 | void tt_commit_changes(struct bat_priv *bat_priv) | ||
1709 | { | ||
1710 | tt_local_reset_flags(bat_priv, TT_CLIENT_NEW); | ||
1711 | tt_local_purge_pending_clients(bat_priv); | ||
1712 | |||
1713 | /* Increment the TTVN only once per OGM interval */ | ||
1714 | atomic_inc(&bat_priv->ttvn); | ||
1715 | bat_priv->tt_poss_change = false; | ||
1716 | } | ||
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 460e5839cdd6..d4122cba53b8 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h | |||
@@ -61,5 +61,6 @@ void handle_tt_response(struct bat_priv *bat_priv, | |||
61 | struct tt_query_packet *tt_response); | 61 | struct tt_query_packet *tt_response); |
62 | void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, | 62 | void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, |
63 | struct orig_node *orig_node); | 63 | struct orig_node *orig_node); |
64 | void tt_commit_changes(struct bat_priv *bat_priv); | ||
64 | 65 | ||
65 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ | 66 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ |