Commit 058d0e26989e3da2fa031f551235f6ff1e0bc27c

Authored by Antonio Quartulli
Committed by Marek Lindner
1 parent c8c991bf20

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>

Showing 4 changed files with 125 additions and 30 deletions Side-by-side Diff

net/batman-adv/packet.h
... ... @@ -84,7 +84,9 @@
84 84 enum tt_client_flags {
85 85 TT_CLIENT_DEL = 1 << 0,
86 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 92 struct batman_packet {
net/batman-adv/send.c
... ... @@ -309,10 +309,8 @@
309 309 if (hard_iface == primary_if) {
310 310 /* if at least one change happened */
311 311 if (atomic_read(&bat_priv->tt_local_changes) > 0) {
  312 + tt_commit_changes(bat_priv);
312 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 316 /* if the changes have been sent enough times */
net/batman-adv/translation-table.c
... ... @@ -215,11 +215,14 @@
215 215  
216 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 223 hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
219 224 tt_local_entry, &tt_local_entry->hash_entry);
220 225  
221   - atomic_inc(&bat_priv->num_local_tt);
222   -
223 226 /* remove address from global hash if present */
224 227 tt_global_entry = tt_global_hash_find(bat_priv, addr);
225 228  
226 229  
227 230  
... ... @@ -358,19 +361,17 @@
358 361 return ret;
359 362 }
360 363  
361   -static void tt_local_del(struct bat_priv *bat_priv,
362   - struct tt_local_entry *tt_local_entry,
363   - const char *message)
  364 +static void tt_local_set_pending(struct bat_priv *bat_priv,
  365 + struct tt_local_entry *tt_local_entry,
  366 + uint16_t flags)
364 367 {
365   - bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n",
366   - tt_local_entry->addr, message);
  368 + tt_local_event(bat_priv, tt_local_entry->addr,
  369 + tt_local_entry->flags | flags);
367 370  
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   -
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 377 void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
377 378  
... ... @@ -379,14 +380,14 @@
379 380 struct tt_local_entry *tt_local_entry = NULL;
380 381  
381 382 tt_local_entry = tt_local_hash_find(bat_priv, addr);
382   -
383 383 if (!tt_local_entry)
384 384 goto out;
385 385  
386   - tt_local_event(bat_priv, tt_local_entry->addr,
387   - tt_local_entry->flags | TT_CLIENT_DEL |
388   - (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
389   - tt_local_del(bat_priv, tt_local_entry, message);
  386 + tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
  387 + (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
  388 +
  389 + bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
  390 + "%s\n", tt_local_entry->addr, message);
390 391 out:
391 392 if (tt_local_entry)
392 393 tt_local_entry_free_ref(tt_local_entry);
393 394  
394 395  
... ... @@ -411,18 +412,19 @@
411 412 if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
412 413 continue;
413 414  
  415 + /* entry already marked for deletion */
  416 + if (tt_local_entry->flags & TT_CLIENT_PENDING)
  417 + continue;
  418 +
414 419 if (!is_out_of_time(tt_local_entry->last_seen,
415 420 TT_LOCAL_TIMEOUT * 1000))
416 421 continue;
417 422  
418   - tt_local_event(bat_priv, tt_local_entry->addr,
419   - tt_local_entry->flags | TT_CLIENT_DEL);
420   - atomic_dec(&bat_priv->num_local_tt);
421   - bat_dbg(DBG_TT, bat_priv, "Deleting local "
422   - "tt entry (%pM): timed out\n",
  423 + tt_local_set_pending(bat_priv, tt_local_entry,
  424 + TT_CLIENT_DEL);
  425 + bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
  426 + "pending to be removed: timed out\n",
423 427 tt_local_entry->addr);
424   - hlist_del_rcu(node);
425   - tt_local_entry_free_ref(tt_local_entry);
426 428 }
427 429 spin_unlock_bh(list_lock);
428 430 }
... ... @@ -846,6 +848,10 @@
846 848 rcu_read_lock();
847 849 hlist_for_each_entry_rcu(tt_local_entry, node,
848 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 855 total_one = 0;
850 856 for (j = 0; j < ETH_ALEN; j++)
851 857 total_one = crc16_byte(total_one,
... ... @@ -935,6 +941,16 @@
935 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 954 static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
939 955 {
940 956 const struct tt_global_entry *tt_global_entry = entry_ptr;
... ... @@ -1275,7 +1291,8 @@
1275 1291  
1276 1292 skb = tt_response_fill_table(tt_len, ttvn,
1277 1293 bat_priv->tt_local_hash,
1278   - primary_if, NULL, NULL);
  1294 + primary_if, tt_local_valid_entry,
  1295 + NULL);
1279 1296 if (!skb)
1280 1297 goto out;
1281 1298  
... ... @@ -1400,6 +1417,10 @@
1400 1417 tt_local_entry = tt_local_hash_find(bat_priv, addr);
1401 1418 if (!tt_local_entry)
1402 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 1424 ret = true;
1404 1425 out:
1405 1426 if (tt_local_entry)
... ... @@ -1619,5 +1640,78 @@
1619 1640 tt_roam_list_free(bat_priv);
1620 1641  
1621 1642 kfree(bat_priv->tt_buff);
  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;
1622 1716 }
net/batman-adv/translation-table.h
... ... @@ -61,6 +61,7 @@
61 61 struct tt_query_packet *tt_response);
62 62 void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
63 63 struct orig_node *orig_node);
  64 +void tt_commit_changes(struct bat_priv *bat_priv);
64 65  
65 66 #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */