| From: Marek Lindner <mareklindner@neomailbox.ch> |
| Date: Sat, 12 May 2018 00:23:07 +0800 |
| Subject: batman-adv: prevent TT request storms by not sending inconsistent TT |
| TLVLs |
| |
| commit 16116dac23396e73c01eeee97b102e4833a4b205 upstream. |
| |
| A translation table TVLV changset sent with an OGM consists |
| of a number of headers (one per VLAN) plus the changeset |
| itself (addition and/or deletion of entries). |
| |
| The per-VLAN headers are used by OGM recipients for consistency |
| checks. Said consistency check might determine that a full |
| translation table request is needed to restore consistency. If |
| the TT sender adds per-VLAN headers of empty VLANs into the OGM, |
| recipients are led to believe to have reached an inconsistent |
| state and thus request a full table update. The full table does |
| not contain empty VLANs (due to missing entries) the cycle |
| restarts when the next OGM is issued. |
| |
| Consequently, when the translation table TVLV headers are |
| composed, empty VLANs are to be excluded. |
| |
| Fixes: 21a57f6e7a3b ("batman-adv: make the TT CRC logic VLAN specific") |
| Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch> |
| Signed-off-by: Sven Eckelmann <sven@narfation.org> |
| Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de> |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| --- a/net/batman-adv/translation-table.c |
| +++ b/net/batman-adv/translation-table.c |
| @@ -786,14 +786,21 @@ batadv_tt_prepare_tvlv_local_data(struct |
| { |
| struct batadv_tvlv_tt_vlan_data *tt_vlan; |
| struct batadv_softif_vlan *vlan; |
| - uint16_t num_vlan = 0, num_entries = 0, tvlv_len; |
| + u16 num_vlan = 0; |
| + u16 vlan_entries = 0; |
| + u16 total_entries = 0; |
| + u16 tvlv_len; |
| uint8_t *tt_change_ptr; |
| int change_offset; |
| |
| spin_lock_bh(&bat_priv->softif_vlan_list_lock); |
| hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { |
| + vlan_entries = atomic_read(&vlan->tt.num_entries); |
| + if (vlan_entries < 1) |
| + continue; |
| + |
| num_vlan++; |
| - num_entries += atomic_read(&vlan->tt.num_entries); |
| + total_entries += vlan_entries; |
| } |
| |
| change_offset = sizeof(**tt_data); |
| @@ -801,7 +808,7 @@ batadv_tt_prepare_tvlv_local_data(struct |
| |
| /* if tt_len is negative, allocate the space needed by the full table */ |
| if (*tt_len < 0) |
| - *tt_len = batadv_tt_len(num_entries); |
| + *tt_len = batadv_tt_len(total_entries); |
| |
| tvlv_len = *tt_len; |
| tvlv_len += change_offset; |
| @@ -818,6 +825,10 @@ batadv_tt_prepare_tvlv_local_data(struct |
| |
| tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); |
| hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { |
| + vlan_entries = atomic_read(&vlan->tt.num_entries); |
| + if (vlan_entries < 1) |
| + continue; |
| + |
| tt_vlan->vid = htons(vlan->vid); |
| tt_vlan->crc = htonl(vlan->tt.crc); |
| |