aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-07-08 11:44:57 -0400
committerDavid S. Miller <davem@davemloft.net>2011-07-08 11:44:57 -0400
commit3f9aed7c7d517dbc717a97649d0a5a9dc80bf4f2 (patch)
treebed215245dc32aea477c76f7124e6af13ba362ac /net/batman-adv
parent31817df025e24559a01d33ddd68bd11b21bf9d7b (diff)
parenta7f9becb7d27008af0f72f8449c110276b0df37d (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.c2
-rw-r--r--net/batman-adv/packet.h4
-rw-r--r--net/batman-adv/routing.c12
-rw-r--r--net/batman-adv/send.c4
-rw-r--r--net/batman-adv/translation-table.c156
-rw-r--r--net/batman-adv/translation-table.h1
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 {
84enum tt_client_flags { 84enum 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
90struct batman_packet { 92struct 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
361static void tt_local_del(struct bat_priv *bat_priv, 365static 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
376void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, 378void 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);
390out: 392out:
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
790free_tt: 798free_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 */
951static 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
938static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) 960static 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;
1404out: 1431out:
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 */
1654static 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 */
1680static 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
1714void 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);
62void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 62void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
63 struct orig_node *orig_node); 63 struct orig_node *orig_node);
64void 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_ */