Some TT flags can change at runtime and for this reason all the nodes in the mesh network must track and possibly update them. An existing example is the Wifi flag.
This patchset introduces all those needed changes in order to synchronize client flags that requires such treatment.
Cheers,
This code is based on top of ordex/tt-vlan
Antonio Quartulli (3): batman-adv: invoke dev_get_by_index() outside of is_wifi_iface() batman-adv: improve TT component to support runtime flag changes batman-adv: compute the global/local table CRC using the synch flags
hard-interface.c | 33 ++++----------------------------- hard-interface.h | 2 +- packet.h | 14 +++++++++++++- translation-table.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 32 deletions(-)
From: Antonio Quartulli antonio@open-mesh.com
Changes that are going to be introduced later will need to perform other checks on the incoming net_device struct.
To avoid performing the dev_get_by_index() each and every time, it is better to move it outside of the is_wifi_iface() function and then pass the obtained pointer to all the checking routines.
Signed-off-by: Antonio Quartulli antonio@open-mesh.com --- hard-interface.c | 33 ++++----------------------------- hard-interface.h | 2 +- translation-table.c | 8 +++++++- 3 files changed, 12 insertions(+), 31 deletions(-)
diff --git a/hard-interface.c b/hard-interface.c index c343aa8..179f74a 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -124,8 +124,11 @@ static int batadv_is_valid_iface(const struct net_device *net_dev) * * Returns true if the net device is a 802.11 wireless device, false otherwise. */ -static bool batadv_is_wifi_netdev(struct net_device *net_device) +bool batadv_is_wifi_netdev(struct net_device *net_device) { + if (!net_device) + return false; + #ifdef CONFIG_WIRELESS_EXT /* pre-cfg80211 drivers have to implement WEXT, so it is possible to * check for wireless_handlers != NULL @@ -141,34 +144,6 @@ static bool batadv_is_wifi_netdev(struct net_device *net_device) return false; }
-/** - * batadv_is_wifi_iface - check if the given interface represented by ifindex - * is a wifi interface - * @ifindex: interface index to check - * - * Returns true if the interface represented by ifindex is a 802.11 wireless - * device, false otherwise. - */ -bool batadv_is_wifi_iface(int ifindex) -{ - struct net_device *net_device = NULL; - bool ret = false; - - if (ifindex == BATADV_NULL_IFINDEX) - goto out; - - net_device = dev_get_by_index(&init_net, ifindex); - if (!net_device) - goto out; - - ret = batadv_is_wifi_netdev(net_device); - -out: - if (net_device) - dev_put(net_device); - return ret; -} - static struct batadv_hard_iface * batadv_hardif_get_active(const struct net_device *soft_iface) { diff --git a/hard-interface.h b/hard-interface.h index 4989288..2d3488a 100644 --- a/hard-interface.h +++ b/hard-interface.h @@ -51,7 +51,7 @@ void batadv_hardif_remove_interfaces(void); int batadv_hardif_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface); void batadv_hardif_free_rcu(struct rcu_head *rcu); -bool batadv_is_wifi_iface(int ifindex); +bool batadv_is_wifi_netdev(struct net_device *net_device);
static inline void batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) diff --git a/translation-table.c b/translation-table.c index 87c4a44..0543b1a 100644 --- a/translation-table.c +++ b/translation-table.c @@ -346,11 +346,15 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_tt_local_entry *tt_local; struct batadv_tt_global_entry *tt_global; + struct net_device *in_dev = NULL; struct hlist_head *head; struct batadv_tt_orig_list_entry *orig_entry; int hash_added; bool roamed_back = false;
+ if (ifindex != BATADV_NULL_IFINDEX) + in_dev = dev_get_by_index(&init_net, ifindex); + tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
@@ -400,7 +404,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, */ tt_local->common.flags = BATADV_TT_CLIENT_NEW; tt_local->common.vid = vid; - if (batadv_is_wifi_iface(ifindex)) + if (batadv_is_wifi_netdev(in_dev)) tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; atomic_set(&tt_local->common.refcount, 2); tt_local->last_seen = jiffies; @@ -451,6 +455,8 @@ check_roaming: }
out: + if (in_dev) + dev_put(in_dev); if (tt_local) batadv_tt_local_entry_free_ref(tt_local); if (tt_global)
From: Antonio Quartulli antonio@open-mesh.com
The WIFI flag may change (in some rare cases) and get switched after that the related local entry has been already advertised.
Add runtime flag switch detection and re-announce the entry to advertise the new flag values.
By adding this mechanism we allow future flag to be treated the same way.
Signed-off-by: Antonio Quartulli antonio@open-mesh.com --- packet.h | 6 ++++++ translation-table.c | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+)
diff --git a/packet.h b/packet.h index 32ebfbe..02cba21 100644 --- a/packet.h +++ b/packet.h @@ -125,6 +125,12 @@ enum batadv_tt_client_flags { };
/** + * BATADV_TT_REMOTE_MASK - bitmask selecting the flags that are sent over the + * wire only + */ +#define BATADV_TT_REMOTE_MASK 0x00FF + +/** * batadv_vlan_flags - flags for the four MSB of any vlan ID field * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not */ diff --git a/translation-table.c b/translation-table.c index 0543b1a..9dc4207 100644 --- a/translation-table.c +++ b/translation-table.c @@ -269,6 +269,13 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv, goto del; if (del_op_requested && !del_op_entry) goto del; + + /* this is a second add in the same originator interval. It + * means that flags have been changed: update them! + */ + if (!del_op_requested && !del_op_entry) + entry->change.flags = flags; + continue; del: list_del(&entry->list); @@ -350,6 +357,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, struct hlist_head *head; struct batadv_tt_orig_list_entry *orig_entry; int hash_added; + uint8_t remote_flags; bool roamed_back = false;
if (ifindex != BATADV_NULL_IFINDEX) @@ -454,6 +462,21 @@ check_roaming: } }
+ /* store the current remote flags before altering them. This helps + * understanding is flags are changing or not + */ + remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK; + + if (batadv_is_wifi_netdev(in_dev)) + tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; + else + tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; + + /* if any "dynamic" flag has been modified, resend an ADD event for this + * entry so that all the nodes can get the new flags + */ + if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK)) + batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); out: if (in_dev) dev_put(in_dev);
From: Antonio Quartulli antonio@open-mesh.com
Flags selected by TT_SYNCH_MASK are kept in sync among the nodes in the network and therefore they have to be considered while computing the global/local table CRC so that a generic originator is able to realise if its table contains all the correct flags too
Flags from bit 4 to bit 7 are now reserved for synchronized flags only. This allows future developers to add more flags of this type in the future without breaking compatibility again.
Signed-off-by: Antonio Quartulli antonio@open-mesh.com --- packet.h | 8 +++++++- translation-table.c | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/packet.h b/packet.h index 02cba21..dd14c58 100644 --- a/packet.h +++ b/packet.h @@ -117,7 +117,7 @@ enum batadv_tt_data_flags { enum batadv_tt_client_flags { BATADV_TT_CLIENT_DEL = BIT(0), BATADV_TT_CLIENT_ROAM = BIT(1), - BATADV_TT_CLIENT_WIFI = BIT(2), + BATADV_TT_CLIENT_WIFI = BIT(4), BATADV_TT_CLIENT_NOPURGE = BIT(8), BATADV_TT_CLIENT_NEW = BIT(9), BATADV_TT_CLIENT_PENDING = BIT(10), @@ -131,6 +131,12 @@ enum batadv_tt_client_flags { #define BATADV_TT_REMOTE_MASK 0x00FF
/** + * BATADV_TT_SYNCH_MASK - bitmask of the flags that need to be kept in sync + * among the nodes. These flags are used to compute the global/local CRC + */ +#define BATADV_TT_SYNCH_MASK 0x00F0 + +/** * batadv_vlan_flags - flags for the four MSB of any vlan ID field * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not */ diff --git a/translation-table.c b/translation-table.c index 9dc4207..b326983 100644 --- a/translation-table.c +++ b/translation-table.c @@ -1565,6 +1565,7 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global; struct hlist_head *head; uint32_t i, crc_tmp, crc = 0; + uint8_t flags;
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -1597,6 +1598,13 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
crc_tmp = crc32c(0, &tt_common->vid, sizeof(tt_common->vid)); + + /* compute the CRC also over the flags that have to be + * kept in sync among nodes + */ + flags = tt_common->flags & BATADV_TT_SYNCH_MASK; + crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); + crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); } rcu_read_unlock(); @@ -1615,6 +1623,7 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv) struct batadv_tt_common_entry *tt_common; struct hlist_head *head; uint32_t i, crc_tmp, crc = 0; + uint8_t flags;
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -1629,6 +1638,13 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
crc_tmp = crc32c(0, &tt_common->vid, sizeof(tt_common->vid)); + + /* compute the CRC also over the flags that have to be + * kept in sync among nodes + */ + flags = tt_common->flags & BATADV_TT_SYNCH_MASK; + crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); + crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); } rcu_read_unlock(); @@ -2917,6 +2933,9 @@ int batadv_tt_init(struct batadv_priv *bat_priv) { int ret;
+ /* synchronized flags must be remote */ + BUILD_BUG_ON(!(BATADV_TT_SYNCH_MASK & BATADV_TT_REMOTE_MASK)); + ret = batadv_tt_local_init(bat_priv); if (ret < 0) return ret;
b.a.t.m.a.n@lists.open-mesh.org