batman-adv: keep local table consistency for further TT_RESPONSE
authorAntonio Quartulli <ordex@autistici.org>
Wed, 6 Jul 2011 23:40:58 +0000 (01:40 +0200)
committerMarek Lindner <lindner_marek@yahoo.de>
Thu, 7 Jul 2011 16:49:26 +0000 (18:49 +0200)
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>
net/batman-adv/packet.h
net/batman-adv/send.c
net/batman-adv/translation-table.c
net/batman-adv/translation-table.h

index 590e4a66089fbd3ab7bd77aa86a08023bb43fab7..b76b4be10b9270faee2e76506be37026eddde99e 100644 (file)
@@ -84,7 +84,9 @@ enum tt_query_flags {
 enum tt_client_flags {
        TT_CLIENT_DEL     = 1 << 0,
        TT_CLIENT_ROAM    = 1 << 1,
-       TT_CLIENT_NOPURGE = 1 << 8
+       TT_CLIENT_NOPURGE = 1 << 8,
+       TT_CLIENT_NEW     = 1 << 9,
+       TT_CLIENT_PENDING = 1 << 10
 };
 
 struct batman_packet {
index 4b8e11bc14fa656275df364be3438c50aa1713e2..58d14472068cf305b2280426613217008e6480fe 100644 (file)
@@ -309,10 +309,8 @@ void schedule_own_packet(struct hard_iface *hard_iface)
        if (hard_iface == primary_if) {
                /* if at least one change happened */
                if (atomic_read(&bat_priv->tt_local_changes) > 0) {
+                       tt_commit_changes(bat_priv);
                        prepare_packet_buffer(bat_priv, hard_iface);
-                       /* Increment the TTVN only once per OGM interval */
-                       atomic_inc(&bat_priv->ttvn);
-                       bat_priv->tt_poss_change = false;
                }
 
                /* if the changes have been sent enough times */
index 06d361d4ac4b4d93cec09be668236c46e4b6df17..7cc67c0f491519b6d9bcf3ca0a7b76e2bfb7def8 100644 (file)
@@ -215,11 +215,14 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
 
        tt_local_event(bat_priv, addr, tt_local_entry->flags);
 
+       /* The local entry has to be marked as NEW to avoid to send it in
+        * a full table response going out before the next ttvn increment
+        * (consistency check) */
+       tt_local_entry->flags |= TT_CLIENT_NEW;
+
        hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
                 tt_local_entry, &tt_local_entry->hash_entry);
 
-       atomic_inc(&bat_priv->num_local_tt);
-
        /* remove address from global hash if present */
        tt_global_entry = tt_global_hash_find(bat_priv, addr);
 
@@ -358,19 +361,17 @@ out:
        return ret;
 }
 
-static void tt_local_del(struct bat_priv *bat_priv,
-                        struct tt_local_entry *tt_local_entry,
-                        const char *message)
+static void tt_local_set_pending(struct bat_priv *bat_priv,
+                                struct tt_local_entry *tt_local_entry,
+                                uint16_t flags)
 {
-       bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n",
-               tt_local_entry->addr, message);
-
-       atomic_dec(&bat_priv->num_local_tt);
-
-       hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
-                   tt_local_entry->addr);
+       tt_local_event(bat_priv, tt_local_entry->addr,
+                      tt_local_entry->flags | flags);
 
-       tt_local_entry_free_ref(tt_local_entry);
+       /* The local client has to be merked as "pending to be removed" but has
+        * to be kept in the table in order to send it in an full tables
+        * response issued before the net ttvn increment (consistency check) */
+       tt_local_entry->flags |= TT_CLIENT_PENDING;
 }
 
 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,
        struct tt_local_entry *tt_local_entry = NULL;
 
        tt_local_entry = tt_local_hash_find(bat_priv, addr);
-
        if (!tt_local_entry)
                goto out;
 
-       tt_local_event(bat_priv, tt_local_entry->addr,
-                      tt_local_entry->flags | TT_CLIENT_DEL |
-                      (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
-       tt_local_del(bat_priv, tt_local_entry, message);
+       tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
+                            (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
+
+       bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
+               "%s\n", tt_local_entry->addr, message);
 out:
        if (tt_local_entry)
                tt_local_entry_free_ref(tt_local_entry);
@@ -411,18 +412,19 @@ static void tt_local_purge(struct bat_priv *bat_priv)
                        if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
                                continue;
 
+                       /* entry already marked for deletion */
+                       if (tt_local_entry->flags & TT_CLIENT_PENDING)
+                               continue;
+
                        if (!is_out_of_time(tt_local_entry->last_seen,
                                            TT_LOCAL_TIMEOUT * 1000))
                                continue;
 
-                       tt_local_event(bat_priv, tt_local_entry->addr,
-                                      tt_local_entry->flags | TT_CLIENT_DEL);
-                       atomic_dec(&bat_priv->num_local_tt);
-                       bat_dbg(DBG_TT, bat_priv, "Deleting local "
-                               "tt entry (%pM): timed out\n",
+                       tt_local_set_pending(bat_priv, tt_local_entry,
+                                            TT_CLIENT_DEL);
+                       bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
+                               "pending to be removed: timed out\n",
                                tt_local_entry->addr);
-                       hlist_del_rcu(node);
-                       tt_local_entry_free_ref(tt_local_entry);
                }
                spin_unlock_bh(list_lock);
        }
@@ -846,6 +848,10 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv)
                rcu_read_lock();
                hlist_for_each_entry_rcu(tt_local_entry, node,
                                         head, hash_entry) {
+                       /* not yet committed clients have not to be taken into
+                        * account while computing the CRC */
+                       if (tt_local_entry->flags & TT_CLIENT_NEW)
+                               continue;
                        total_one = 0;
                        for (j = 0; j < ETH_ALEN; j++)
                                total_one = crc16_byte(total_one,
@@ -935,6 +941,16 @@ unlock:
        return tt_req_node;
 }
 
+/* data_ptr is useless here, but has to be kept to respect the prototype */
+static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
+{
+       const struct tt_local_entry *tt_local_entry = entry_ptr;
+
+       if (tt_local_entry->flags & TT_CLIENT_NEW)
+               return 0;
+       return 1;
+}
+
 static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
 {
        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,
 
                skb = tt_response_fill_table(tt_len, ttvn,
                                             bat_priv->tt_local_hash,
-                                            primary_if, NULL, NULL);
+                                            primary_if, tt_local_valid_entry,
+                                            NULL);
                if (!skb)
                        goto out;
 
@@ -1400,6 +1417,10 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
        tt_local_entry = tt_local_hash_find(bat_priv, addr);
        if (!tt_local_entry)
                goto out;
+       /* Check if the client has been logically deleted (but is kept for
+        * consistency purpose) */
+       if (tt_local_entry->flags & TT_CLIENT_PENDING)
+               goto out;
        ret = true;
 out:
        if (tt_local_entry)
@@ -1620,3 +1641,76 @@ void tt_free(struct bat_priv *bat_priv)
 
        kfree(bat_priv->tt_buff);
 }
+
+/* This function will reset the specified flags from all the entries in
+ * the given hash table and will increment num_local_tt for each involved
+ * entry */
+static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
+{
+       int i;
+       struct hashtable_t *hash = bat_priv->tt_local_hash;
+       struct hlist_head *head;
+       struct hlist_node *node;
+       struct tt_local_entry *tt_local_entry;
+
+       if (!hash)
+               return;
+
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+
+               rcu_read_lock();
+               hlist_for_each_entry_rcu(tt_local_entry, node,
+                                        head, hash_entry) {
+                       tt_local_entry->flags &= ~flags;
+                       atomic_inc(&bat_priv->num_local_tt);
+               }
+               rcu_read_unlock();
+       }
+
+}
+
+/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
+static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
+{
+       struct hashtable_t *hash = bat_priv->tt_local_hash;
+       struct tt_local_entry *tt_local_entry;
+       struct hlist_node *node, *node_tmp;
+       struct hlist_head *head;
+       spinlock_t *list_lock; /* protects write access to the hash lists */
+       int i;
+
+       if (!hash)
+               return;
+
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+               list_lock = &hash->list_locks[i];
+
+               spin_lock_bh(list_lock);
+               hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
+                                         head, hash_entry) {
+                       if (!(tt_local_entry->flags & TT_CLIENT_PENDING))
+                               continue;
+
+                       bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
+                               "(%pM): pending\n", tt_local_entry->addr);
+
+                       atomic_dec(&bat_priv->num_local_tt);
+                       hlist_del_rcu(node);
+                       tt_local_entry_free_ref(tt_local_entry);
+               }
+               spin_unlock_bh(list_lock);
+       }
+
+}
+
+void tt_commit_changes(struct bat_priv *bat_priv)
+{
+       tt_local_reset_flags(bat_priv, TT_CLIENT_NEW);
+       tt_local_purge_pending_clients(bat_priv);
+
+       /* Increment the TTVN only once per OGM interval */
+       atomic_inc(&bat_priv->ttvn);
+       bat_priv->tt_poss_change = false;
+}
index 460e5839cdd682e95f4e6c29c966c211dca71775..d4122cba53b8e4a7edd960ffb58596597b03e135 100644 (file)
@@ -61,5 +61,6 @@ void handle_tt_response(struct bat_priv *bat_priv,
                        struct tt_query_packet *tt_response);
 void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
                   struct orig_node *orig_node);
+void tt_commit_changes(struct bat_priv *bat_priv);
 
 #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */