diff options
author | David S. Miller <davem@davemloft.net> | 2011-07-08 11:44:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-07-08 11:44:57 -0400 |
commit | 3f9aed7c7d517dbc717a97649d0a5a9dc80bf4f2 (patch) | |
tree | bed215245dc32aea477c76f7124e6af13ba362ac /net/batman-adv | |
parent | 31817df025e24559a01d33ddd68bd11b21bf9d7b (diff) | |
parent | a7f9becb7d27008af0f72f8449c110276b0df37d (diff) |
Merge branch 'batman-adv/next' of git://git.open-mesh.org/linux-merge
Diffstat (limited to 'net/batman-adv')
-rw-r--r-- | net/batman-adv/originator.c | 2 | ||||
-rw-r--r-- | net/batman-adv/packet.h | 4 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 12 | ||||
-rw-r--r-- | net/batman-adv/send.c | 4 | ||||
-rw-r--r-- | net/batman-adv/translation-table.c | 156 | ||||
-rw-r--r-- | net/batman-adv/translation-table.h | 1 |
6 files changed, 147 insertions, 32 deletions
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 4cc94d4ba890..f3c3f620d195 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -223,6 +223,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr) | |||
223 | orig_node->bat_priv = bat_priv; | 223 | orig_node->bat_priv = bat_priv; |
224 | memcpy(orig_node->orig, addr, ETH_ALEN); | 224 | memcpy(orig_node->orig, addr, ETH_ALEN); |
225 | orig_node->router = NULL; | 225 | orig_node->router = NULL; |
226 | orig_node->tt_crc = 0; | ||
227 | atomic_set(&orig_node->last_ttvn, 0); | ||
226 | orig_node->tt_buff = NULL; | 228 | orig_node->tt_buff = NULL; |
227 | orig_node->tt_buff_len = 0; | 229 | orig_node->tt_buff_len = 0; |
228 | atomic_set(&orig_node->tt_size, 0); | 230 | atomic_set(&orig_node->tt_size, 0); |
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/routing.c b/net/batman-adv/routing.c index 2cb98bed1586..0f32c818874d 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -91,6 +91,18 @@ static void update_transtable(struct bat_priv *bat_priv, | |||
91 | * to recompute it to spot any possible inconsistency | 91 | * to recompute it to spot any possible inconsistency |
92 | * in the global table */ | 92 | * in the global table */ |
93 | orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); | 93 | orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); |
94 | |||
95 | /* The ttvn alone is not enough to guarantee consistency | ||
96 | * because a single value could repesent different states | ||
97 | * (due to the wrap around). Thus a node has to check whether | ||
98 | * the resulting table (after applying the changes) is still | ||
99 | * consistent or not. E.g. a node could disconnect while its | ||
100 | * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case | ||
101 | * checking the CRC value is mandatory to detect the | ||
102 | * inconsistency */ | ||
103 | if (orig_node->tt_crc != tt_crc) | ||
104 | goto request_table; | ||
105 | |||
94 | /* Roaming phase is over: tables are in sync again. I can | 106 | /* Roaming phase is over: tables are in sync again. I can |
95 | * unset the flag */ | 107 | * unset the flag */ |
96 | orig_node->tt_poss_change = false; | 108 | orig_node->tt_poss_change = false; |
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..fb6931d00cd7 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 | ||
@@ -227,8 +230,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) | |||
227 | if (tt_global_entry) { | 230 | if (tt_global_entry) { |
228 | /* This node is probably going to update its tt table */ | 231 | /* This node is probably going to update its tt table */ |
229 | tt_global_entry->orig_node->tt_poss_change = true; | 232 | tt_global_entry->orig_node->tt_poss_change = true; |
230 | _tt_global_del(bat_priv, tt_global_entry, | 233 | /* The global entry has to be marked as PENDING and has to be |
231 | "local tt received"); | 234 | * kept for consistency purpose */ |
235 | tt_global_entry->flags |= TT_CLIENT_PENDING; | ||
232 | send_roam_adv(bat_priv, tt_global_entry->addr, | 236 | send_roam_adv(bat_priv, tt_global_entry->addr, |
233 | tt_global_entry->orig_node); | 237 | tt_global_entry->orig_node); |
234 | } | 238 | } |
@@ -358,19 +362,17 @@ out: | |||
358 | return ret; | 362 | return ret; |
359 | } | 363 | } |
360 | 364 | ||
361 | static void tt_local_del(struct bat_priv *bat_priv, | 365 | static void tt_local_set_pending(struct bat_priv *bat_priv, |
362 | struct tt_local_entry *tt_local_entry, | 366 | struct tt_local_entry *tt_local_entry, |
363 | const char *message) | 367 | uint16_t flags) |
364 | { | 368 | { |
365 | bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n", | 369 | tt_local_event(bat_priv, tt_local_entry->addr, |
366 | tt_local_entry->addr, message); | 370 | 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 | 371 | ||
373 | tt_local_entry_free_ref(tt_local_entry); | 372 | /* The local client has to be merked as "pending to be removed" but has |
373 | * to be kept in the table in order to send it in an full tables | ||
374 | * response issued before the net ttvn increment (consistency check) */ | ||
375 | tt_local_entry->flags |= TT_CLIENT_PENDING; | ||
374 | } | 376 | } |
375 | 377 | ||
376 | void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, | 378 | 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, | |||
379 | struct tt_local_entry *tt_local_entry = NULL; | 381 | struct tt_local_entry *tt_local_entry = NULL; |
380 | 382 | ||
381 | tt_local_entry = tt_local_hash_find(bat_priv, addr); | 383 | tt_local_entry = tt_local_hash_find(bat_priv, addr); |
382 | |||
383 | if (!tt_local_entry) | 384 | if (!tt_local_entry) |
384 | goto out; | 385 | goto out; |
385 | 386 | ||
386 | tt_local_event(bat_priv, tt_local_entry->addr, | 387 | tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | |
387 | tt_local_entry->flags | TT_CLIENT_DEL | | 388 | (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); |
388 | (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); | 389 | |
389 | tt_local_del(bat_priv, tt_local_entry, message); | 390 | bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " |
391 | "%s\n", tt_local_entry->addr, message); | ||
390 | out: | 392 | out: |
391 | if (tt_local_entry) | 393 | if (tt_local_entry) |
392 | tt_local_entry_free_ref(tt_local_entry); | 394 | tt_local_entry_free_ref(tt_local_entry); |
@@ -411,18 +413,19 @@ static void tt_local_purge(struct bat_priv *bat_priv) | |||
411 | if (tt_local_entry->flags & TT_CLIENT_NOPURGE) | 413 | if (tt_local_entry->flags & TT_CLIENT_NOPURGE) |
412 | continue; | 414 | continue; |
413 | 415 | ||
416 | /* entry already marked for deletion */ | ||
417 | if (tt_local_entry->flags & TT_CLIENT_PENDING) | ||
418 | continue; | ||
419 | |||
414 | if (!is_out_of_time(tt_local_entry->last_seen, | 420 | if (!is_out_of_time(tt_local_entry->last_seen, |
415 | TT_LOCAL_TIMEOUT * 1000)) | 421 | TT_LOCAL_TIMEOUT * 1000)) |
416 | continue; | 422 | continue; |
417 | 423 | ||
418 | tt_local_event(bat_priv, tt_local_entry->addr, | 424 | tt_local_set_pending(bat_priv, tt_local_entry, |
419 | tt_local_entry->flags | TT_CLIENT_DEL); | 425 | TT_CLIENT_DEL); |
420 | atomic_dec(&bat_priv->num_local_tt); | 426 | bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) " |
421 | bat_dbg(DBG_TT, bat_priv, "Deleting local " | 427 | "pending to be removed: timed out\n", |
422 | "tt entry (%pM): timed out\n", | ||
423 | tt_local_entry->addr); | 428 | tt_local_entry->addr); |
424 | hlist_del_rcu(node); | ||
425 | tt_local_entry_free_ref(tt_local_entry); | ||
426 | } | 429 | } |
427 | spin_unlock_bh(list_lock); | 430 | spin_unlock_bh(list_lock); |
428 | } | 431 | } |
@@ -785,6 +788,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, | |||
785 | if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) | 788 | if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) |
786 | goto free_tt; | 789 | goto free_tt; |
787 | 790 | ||
791 | /* A global client marked as PENDING has already moved from that | ||
792 | * originator */ | ||
793 | if (tt_global_entry->flags & TT_CLIENT_PENDING) | ||
794 | goto free_tt; | ||
795 | |||
788 | orig_node = tt_global_entry->orig_node; | 796 | orig_node = tt_global_entry->orig_node; |
789 | 797 | ||
790 | free_tt: | 798 | free_tt: |
@@ -846,6 +854,10 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv) | |||
846 | rcu_read_lock(); | 854 | rcu_read_lock(); |
847 | hlist_for_each_entry_rcu(tt_local_entry, node, | 855 | hlist_for_each_entry_rcu(tt_local_entry, node, |
848 | head, hash_entry) { | 856 | head, hash_entry) { |
857 | /* not yet committed clients have not to be taken into | ||
858 | * account while computing the CRC */ | ||
859 | if (tt_local_entry->flags & TT_CLIENT_NEW) | ||
860 | continue; | ||
849 | total_one = 0; | 861 | total_one = 0; |
850 | for (j = 0; j < ETH_ALEN; j++) | 862 | for (j = 0; j < ETH_ALEN; j++) |
851 | total_one = crc16_byte(total_one, | 863 | total_one = crc16_byte(total_one, |
@@ -935,6 +947,16 @@ unlock: | |||
935 | return tt_req_node; | 947 | return tt_req_node; |
936 | } | 948 | } |
937 | 949 | ||
950 | /* data_ptr is useless here, but has to be kept to respect the prototype */ | ||
951 | static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr) | ||
952 | { | ||
953 | const struct tt_local_entry *tt_local_entry = entry_ptr; | ||
954 | |||
955 | if (tt_local_entry->flags & TT_CLIENT_NEW) | ||
956 | return 0; | ||
957 | return 1; | ||
958 | } | ||
959 | |||
938 | static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) | 960 | static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) |
939 | { | 961 | { |
940 | const struct tt_global_entry *tt_global_entry = entry_ptr; | 962 | 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, | |||
1275 | 1297 | ||
1276 | skb = tt_response_fill_table(tt_len, ttvn, | 1298 | skb = tt_response_fill_table(tt_len, ttvn, |
1277 | bat_priv->tt_local_hash, | 1299 | bat_priv->tt_local_hash, |
1278 | primary_if, NULL, NULL); | 1300 | primary_if, tt_local_valid_entry, |
1301 | NULL); | ||
1279 | if (!skb) | 1302 | if (!skb) |
1280 | goto out; | 1303 | goto out; |
1281 | 1304 | ||
@@ -1400,6 +1423,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); | 1423 | tt_local_entry = tt_local_hash_find(bat_priv, addr); |
1401 | if (!tt_local_entry) | 1424 | if (!tt_local_entry) |
1402 | goto out; | 1425 | goto out; |
1426 | /* Check if the client has been logically deleted (but is kept for | ||
1427 | * consistency purpose) */ | ||
1428 | if (tt_local_entry->flags & TT_CLIENT_PENDING) | ||
1429 | goto out; | ||
1403 | ret = true; | 1430 | ret = true; |
1404 | out: | 1431 | out: |
1405 | if (tt_local_entry) | 1432 | if (tt_local_entry) |
@@ -1620,3 +1647,76 @@ void tt_free(struct bat_priv *bat_priv) | |||
1620 | 1647 | ||
1621 | kfree(bat_priv->tt_buff); | 1648 | kfree(bat_priv->tt_buff); |
1622 | } | 1649 | } |
1650 | |||
1651 | /* This function will reset the specified flags from all the entries in | ||
1652 | * the given hash table and will increment num_local_tt for each involved | ||
1653 | * entry */ | ||
1654 | static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags) | ||
1655 | { | ||
1656 | int i; | ||
1657 | struct hashtable_t *hash = bat_priv->tt_local_hash; | ||
1658 | struct hlist_head *head; | ||
1659 | struct hlist_node *node; | ||
1660 | struct tt_local_entry *tt_local_entry; | ||
1661 | |||
1662 | if (!hash) | ||
1663 | return; | ||
1664 | |||
1665 | for (i = 0; i < hash->size; i++) { | ||
1666 | head = &hash->table[i]; | ||
1667 | |||
1668 | rcu_read_lock(); | ||
1669 | hlist_for_each_entry_rcu(tt_local_entry, node, | ||
1670 | head, hash_entry) { | ||
1671 | tt_local_entry->flags &= ~flags; | ||
1672 | atomic_inc(&bat_priv->num_local_tt); | ||
1673 | } | ||
1674 | rcu_read_unlock(); | ||
1675 | } | ||
1676 | |||
1677 | } | ||
1678 | |||
1679 | /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ | ||
1680 | static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) | ||
1681 | { | ||
1682 | struct hashtable_t *hash = bat_priv->tt_local_hash; | ||
1683 | struct tt_local_entry *tt_local_entry; | ||
1684 | struct hlist_node *node, *node_tmp; | ||
1685 | struct hlist_head *head; | ||
1686 | spinlock_t *list_lock; /* protects write access to the hash lists */ | ||
1687 | int i; | ||
1688 | |||
1689 | if (!hash) | ||
1690 | return; | ||
1691 | |||
1692 | for (i = 0; i < hash->size; i++) { | ||
1693 | head = &hash->table[i]; | ||
1694 | list_lock = &hash->list_locks[i]; | ||
1695 | |||
1696 | spin_lock_bh(list_lock); | ||
1697 | hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, | ||
1698 | head, hash_entry) { | ||
1699 | if (!(tt_local_entry->flags & TT_CLIENT_PENDING)) | ||
1700 | continue; | ||
1701 | |||
1702 | bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " | ||
1703 | "(%pM): pending\n", tt_local_entry->addr); | ||
1704 | |||
1705 | atomic_dec(&bat_priv->num_local_tt); | ||
1706 | hlist_del_rcu(node); | ||
1707 | tt_local_entry_free_ref(tt_local_entry); | ||
1708 | } | ||
1709 | spin_unlock_bh(list_lock); | ||
1710 | } | ||
1711 | |||
1712 | } | ||
1713 | |||
1714 | void tt_commit_changes(struct bat_priv *bat_priv) | ||
1715 | { | ||
1716 | tt_local_reset_flags(bat_priv, TT_CLIENT_NEW); | ||
1717 | tt_local_purge_pending_clients(bat_priv); | ||
1718 | |||
1719 | /* Increment the TTVN only once per OGM interval */ | ||
1720 | atomic_inc(&bat_priv->ttvn); | ||
1721 | bat_priv->tt_poss_change = false; | ||
1722 | } | ||
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_ */ |