aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/translation-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/translation-table.c')
-rw-r--r--net/batman-adv/translation-table.c156
1 files changed, 128 insertions, 28 deletions
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}