Commit dee222c7 authored by Sven Eckelmann's avatar Sven Eckelmann Committed by Simon Wunderlich

batman-adv: Move OGM rebroadcast stats to orig_ifinfo

B.A.T.M.A.N. IV requires the number of rebroadcast from a neighboring
originator. These statistics are gathered per interface which transmitted
the OGM (and then received it again). Since an originator is not interface
specific, a resizable array was used in each originator.

This resizable array had an entry for each interface and had to be resizes
(for all OGMs) when the number of active interface was modified. This could
cause problems when a large number of interface is added and not enough
continuous memory is available to allocate the array.

There is already a per interface originator structure "batadv_orig_ifinfo"
which can be used to store this information.
Signed-off-by: default avatarSven Eckelmann <sven@narfation.org>
Signed-off-by: default avatarSimon Wunderlich <sw@simonwunderlich.de>
parent d331a739
This diff is collapsed.
......@@ -763,11 +763,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
hard_iface->soft_iface = soft_iface;
bat_priv = netdev_priv(hard_iface->soft_iface);
if (bat_priv->num_ifaces >= UINT_MAX) {
ret = -ENOSPC;
goto err_dev;
}
ret = netdev_master_upper_dev_link(hard_iface->net_dev,
soft_iface, NULL, NULL, NULL);
if (ret)
......@@ -777,16 +772,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (ret < 0)
goto err_upper;
hard_iface->if_num = bat_priv->num_ifaces;
bat_priv->num_ifaces++;
hard_iface->if_status = BATADV_IF_INACTIVE;
ret = batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
if (ret < 0) {
bat_priv->algo_ops->iface.disable(hard_iface);
bat_priv->num_ifaces--;
hard_iface->if_status = BATADV_IF_NOT_IN_USE;
goto err_upper;
}
kref_get(&hard_iface->refcount);
hard_iface->batman_adv_ptype.type = ethertype;
......@@ -833,6 +819,33 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
return ret;
}
/**
* batadv_hardif_cnt() - get number of interfaces enslaved to soft interface
* @soft_iface: soft interface to check
*
* This function is only using RCU for locking - the result can therefore be
* off when another functions is modifying the list at the same time. The
* caller can use the rtnl_lock to make sure that the count is accurate.
*
* Return: number of connected/enslaved hard interfaces
*/
static size_t batadv_hardif_cnt(const struct net_device *soft_iface)
{
struct batadv_hard_iface *hard_iface;
size_t count = 0;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->soft_iface != soft_iface)
continue;
count++;
}
rcu_read_unlock();
return count;
}
/**
* batadv_hardif_disable_interface() - Remove hard interface from soft interface
* @hard_iface: hard interface to be removed
......@@ -855,9 +868,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
dev_remove_pack(&hard_iface->batman_adv_ptype);
batadv_hardif_put(hard_iface);
bat_priv->num_ifaces--;
batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
primary_if = batadv_primary_if_get_selected(bat_priv);
if (hard_iface == primary_if) {
struct batadv_hard_iface *new_if;
......@@ -881,7 +891,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface);
/* nobody uses this interface anymore */
if (bat_priv->num_ifaces == 0) {
if (batadv_hardif_cnt(hard_iface->soft_iface) <= 1) {
batadv_gw_check_client_stop(bat_priv);
if (autodel == BATADV_IF_CLEANUP_AUTO)
......@@ -917,7 +927,6 @@ batadv_hardif_add_interface(struct net_device *net_dev)
if (ret)
goto free_if;
hard_iface->if_num = 0;
hard_iface->net_dev = net_dev;
hard_iface->soft_iface = NULL;
hard_iface->if_status = BATADV_IF_NOT_IN_USE;
......
......@@ -904,9 +904,6 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
batadv_frag_purge_orig(orig_node, NULL);
if (orig_node->bat_priv->algo_ops->orig.free)
orig_node->bat_priv->algo_ops->orig.free(orig_node);
kfree(orig_node->tt_buff);
kfree(orig_node);
}
......@@ -1555,107 +1552,3 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb)
return ret;
}
/**
* batadv_orig_hash_add_if() - Add interface to originators in orig_hash
* @hard_iface: hard interface to add (already slave of the soft interface)
* @max_if_num: new number of interfaces
*
* Return: 0 on success or negative error number in case of failure
*/
int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
unsigned int max_if_num)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct batadv_algo_ops *bao = bat_priv->algo_ops;
struct batadv_hashtable *hash = bat_priv->orig_hash;
struct hlist_head *head;
struct batadv_orig_node *orig_node;
u32 i;
int ret;
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num
*/
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
ret = 0;
if (bao->orig.add_if)
ret = bao->orig.add_if(orig_node, max_if_num);
if (ret == -ENOMEM)
goto err;
}
rcu_read_unlock();
}
return 0;
err:
rcu_read_unlock();
return -ENOMEM;
}
/**
* batadv_orig_hash_del_if() - Remove interface from originators in orig_hash
* @hard_iface: hard interface to remove (still slave of the soft interface)
* @max_if_num: new number of interfaces
*
* Return: 0 on success or negative error number in case of failure
*/
int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
unsigned int max_if_num)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct batadv_hashtable *hash = bat_priv->orig_hash;
struct hlist_head *head;
struct batadv_hard_iface *hard_iface_tmp;
struct batadv_orig_node *orig_node;
struct batadv_algo_ops *bao = bat_priv->algo_ops;
u32 i;
int ret;
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num
*/
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
ret = 0;
if (bao->orig.del_if)
ret = bao->orig.del_if(orig_node, max_if_num,
hard_iface->if_num);
if (ret == -ENOMEM)
goto err;
}
rcu_read_unlock();
}
/* renumber remaining batman interfaces _inside_ of orig_hash_lock */
rcu_read_lock();
list_for_each_entry_rcu(hard_iface_tmp, &batadv_hardif_list, list) {
if (hard_iface_tmp->if_status == BATADV_IF_NOT_IN_USE)
continue;
if (hard_iface == hard_iface_tmp)
continue;
if (hard_iface->soft_iface != hard_iface_tmp->soft_iface)
continue;
if (hard_iface_tmp->if_num > hard_iface->if_num)
hard_iface_tmp->if_num--;
}
rcu_read_unlock();
hard_iface->if_num = -1;
return 0;
err:
rcu_read_unlock();
return -ENOMEM;
}
......@@ -72,10 +72,6 @@ void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo);
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb);
int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
unsigned int max_if_num);
int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
unsigned int max_if_num);
struct batadv_orig_node_vlan *
batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
unsigned short vid);
......
......@@ -833,7 +833,6 @@ static int batadv_softif_init_late(struct net_device *dev)
atomic_set(&bat_priv->frag_seqno, random_seqno);
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
batadv_nc_init_bat_priv(bat_priv);
......
......@@ -167,9 +167,6 @@ struct batadv_hard_iface {
/** @list: list node for batadv_hardif_list */
struct list_head list;
/** @if_num: identificator of the interface */
unsigned int if_num;
/** @if_status: status of the interface for batman-adv */
char if_status;
......@@ -232,6 +229,20 @@ struct batadv_hard_iface {
spinlock_t neigh_list_lock;
};
/**
* struct batadv_orig_ifinfo - B.A.T.M.A.N. IV private orig_ifinfo members
*/
struct batadv_orig_ifinfo_bat_iv {
/**
* @bcast_own: bitfield which counts the number of our OGMs this
* orig_node rebroadcasted "back" to us (relative to last_real_seqno)
*/
DECLARE_BITMAP(bcast_own, BATADV_TQ_LOCAL_WINDOW_SIZE);
/** @bcast_own_sum: sum of bcast_own */
u8 bcast_own_sum;
};
/**
* struct batadv_orig_ifinfo - originator info per outgoing interface
*/
......@@ -257,6 +268,9 @@ struct batadv_orig_ifinfo {
/** @batman_seqno_reset: time when the batman seqno window was reset */
unsigned long batman_seqno_reset;
/** @bat_iv: B.A.T.M.A.N. IV private structure */
struct batadv_orig_ifinfo_bat_iv bat_iv;
/** @refcount: number of contexts the object is used */
struct kref refcount;
......@@ -339,19 +353,10 @@ struct batadv_orig_node_vlan {
*/
struct batadv_orig_bat_iv {
/**
* @bcast_own: set of bitfields (one per hard-interface) where each one
* counts the number of our OGMs this orig_node rebroadcasted "back" to
* us (relative to last_real_seqno). Every bitfield is
* BATADV_TQ_LOCAL_WINDOW_SIZE bits long.
*/
unsigned long *bcast_own;
/** @bcast_own_sum: sum of bcast_own */
u8 *bcast_own_sum;
/**
* @ogm_cnt_lock: lock protecting bcast_own, bcast_own_sum,
* neigh_node->bat_iv.real_bits & neigh_node->bat_iv.real_packet_count
* @ogm_cnt_lock: lock protecting &batadv_orig_ifinfo_bat_iv.bcast_own,
* &batadv_orig_ifinfo_bat_iv.bcast_own_sum,
* &batadv_neigh_ifinfo_bat_iv.bat_iv.real_bits and
* &batadv_neigh_ifinfo_bat_iv.real_packet_count
*/
spinlock_t ogm_cnt_lock;
};
......@@ -1597,9 +1602,6 @@ struct batadv_priv {
/** @batman_queue_left: number of remaining OGM packet slots */
atomic_t batman_queue_left;
/** @num_ifaces: number of interfaces assigned to this mesh interface */
unsigned int num_ifaces;
/** @mesh_obj: kobject for sysfs mesh subdirectory */
struct kobject *mesh_obj;
......@@ -2179,28 +2181,6 @@ struct batadv_algo_neigh_ops {
* struct batadv_algo_orig_ops - mesh algorithm callbacks (originator specific)
*/
struct batadv_algo_orig_ops {
/**
* @free: free the resources allocated by the routing algorithm for an
* orig_node object (optional)
*/
void (*free)(struct batadv_orig_node *orig_node);
/**
* @add_if: ask the routing algorithm to apply the needed changes to the
* orig_node due to a new hard-interface being added into the mesh
* (optional)
*/
int (*add_if)(struct batadv_orig_node *orig_node,
unsigned int max_if_num);
/**
* @del_if: ask the routing algorithm to apply the needed changes to the
* orig_node due to an hard-interface being removed from the mesh
* (optional)
*/
int (*del_if)(struct batadv_orig_node *orig_node,
unsigned int max_if_num, unsigned int del_if_num);
#ifdef CONFIG_BATMAN_ADV_DEBUGFS
/** @print: print the originator table (optional) */
void (*print)(struct batadv_priv *priv, struct seq_file *seq,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment