Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ea7b4a1 authored by Antonio Quartulli's avatar Antonio Quartulli Committed by Antonio Quartulli
Browse files

batman-adv: make the TT CRC logic VLAN specific



This change allows nodes to handle the TT table on a
per-VLAN basis. This is needed because nodes may have to
store only some of the global entries advertised by another
node.

In this scenario such nodes would re-create only a partial
global table and would not be able to compute a correct CRC
anymore.

This patch splits the logic and introduces one CRC per VLAN.
In this way a node fetching only some entries belonging to
some VLANs is still able to compute the needed CRCs and
still check the table correctness.

With this patch the shape of the TVLV-TT is changed too
because now a node needs to advertise all the CRCs of all
the VLANs that it is wired to.

The debug output of the local Translation Table now shows
the CRC along with each entry since there is not a common
value for the entire table anymore.

Signed-off-by: default avatarAntonio Quartulli <antonio@open-mesh.com>
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
parent a70a9aa9
Loading
Loading
Loading
Loading
+98 −3
Original line number Diff line number Diff line
@@ -44,6 +44,88 @@ static int batadv_compare_orig(const struct hlist_node *node, const void *data2)
	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}

/**
 * batadv_orig_node_vlan_get - get an orig_node_vlan object
 * @orig_node: the originator serving the VLAN
 * @vid: the VLAN identifier
 *
 * Returns the vlan object identified by vid and belonging to orig_node or NULL
 * if it does not exist.
 */
struct batadv_orig_node_vlan *
batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,
			  unsigned short vid)
{
	struct batadv_orig_node_vlan *vlan = NULL, *tmp;

	rcu_read_lock();
	list_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) {
		if (tmp->vid != vid)
			continue;

		if (!atomic_inc_not_zero(&tmp->refcount))
			continue;

		vlan = tmp;

		break;
	}
	rcu_read_unlock();

	return vlan;
}

/**
 * batadv_orig_node_vlan_new - search and possibly create an orig_node_vlan
 *  object
 * @orig_node: the originator serving the VLAN
 * @vid: the VLAN identifier
 *
 * Returns NULL in case of failure or the vlan object identified by vid and
 * belonging to orig_node otherwise. The object is created and added to the list
 * if it does not exist.
 *
 * The object is returned with refcounter increased by 1.
 */
struct batadv_orig_node_vlan *
batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
			  unsigned short vid)
{
	struct batadv_orig_node_vlan *vlan;

	spin_lock_bh(&orig_node->vlan_list_lock);

	/* first look if an object for this vid already exists */
	vlan = batadv_orig_node_vlan_get(orig_node, vid);
	if (vlan)
		goto out;

	vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
	if (!vlan)
		goto out;

	atomic_set(&vlan->refcount, 2);
	vlan->vid = vid;

	list_add_rcu(&vlan->list, &orig_node->vlan_list);

out:
	spin_unlock_bh(&orig_node->vlan_list_lock);

	return vlan;
}

/**
 * batadv_orig_node_vlan_free_ref - decrement the refcounter and possibly free
 *  the originator-vlan object
 * @orig_vlan: the originator-vlan object to release
 */
void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan)
{
	if (atomic_dec_and_test(&orig_vlan->refcount))
		kfree_rcu(orig_vlan, rcu);
}

int batadv_originator_init(struct batadv_priv *bat_priv)
{
	if (bat_priv->orig_hash)
@@ -218,6 +300,7 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
					      const uint8_t *addr)
{
	struct batadv_orig_node *orig_node;
	struct batadv_orig_node_vlan *vlan;
	int size, i;
	int hash_added;
	unsigned long reset_time;
@@ -235,11 +318,13 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,

	INIT_HLIST_HEAD(&orig_node->neigh_list);
	INIT_LIST_HEAD(&orig_node->bond_list);
	INIT_LIST_HEAD(&orig_node->vlan_list);
	spin_lock_init(&orig_node->ogm_cnt_lock);
	spin_lock_init(&orig_node->bcast_seqno_lock);
	spin_lock_init(&orig_node->neigh_list_lock);
	spin_lock_init(&orig_node->tt_buff_lock);
	spin_lock_init(&orig_node->tt_lock);
	spin_lock_init(&orig_node->vlan_list_lock);

	batadv_nc_init_orig(orig_node);

@@ -251,22 +336,30 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
	memcpy(orig_node->orig, addr, ETH_ALEN);
	batadv_dat_init_orig_node_addr(orig_node);
	orig_node->router = NULL;
	orig_node->tt_crc = 0;
	atomic_set(&orig_node->last_ttvn, 0);
	orig_node->tt_buff = NULL;
	orig_node->tt_buff_len = 0;
	atomic_set(&orig_node->tt_size, 0);
	reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
	orig_node->bcast_seqno_reset = reset_time;
	orig_node->batman_seqno_reset = reset_time;

	atomic_set(&orig_node->bond_candidates, 0);

	/* create a vlan object for the "untagged" LAN */
	vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
	if (!vlan)
		goto free_orig_node;
	/* batadv_orig_node_vlan_new() increases the refcounter.
	 * Immediately release vlan since it is not needed anymore in this
	 * context
	 */
	batadv_orig_node_vlan_free_ref(vlan);

	size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS;

	orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
	if (!orig_node->bcast_own)
		goto free_orig_node;
		goto free_vlan;

	size = bat_priv->num_ifaces * sizeof(uint8_t);
	orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
@@ -291,6 +384,8 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
	kfree(orig_node->bcast_own_sum);
free_bcast_own:
	kfree(orig_node->bcast_own);
free_vlan:
	batadv_orig_node_vlan_free_ref(vlan);
free_orig_node:
	kfree(orig_node);
	return NULL;
+7 −0
Original line number Diff line number Diff line
@@ -40,6 +40,13 @@ int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
			    int max_if_num);
int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
			    int max_if_num);
struct batadv_orig_node_vlan *
batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
			  unsigned short vid);
struct batadv_orig_node_vlan *
batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,
			  unsigned short vid);
void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan);


/* hashfunction to choose an entry in a hash table of given size
+15 −3
Original line number Diff line number Diff line
@@ -391,14 +391,26 @@ struct batadv_tvlv_gateway_data {
 * struct batadv_tvlv_tt_data - tt data propagated through the tt tvlv container
 * @flags: translation table flags (see batadv_tt_data_flags)
 * @ttvn: translation table version number
 * @reserved: field reserved for future use
 * @crc: crc32 checksum of the local translation table
 * @vlan_num: number of announced VLANs. In the TVLV this struct is followed by
 *  one batadv_tvlv_tt_vlan_data object per announced vlan
 */
struct batadv_tvlv_tt_data {
	uint8_t flags;
	uint8_t ttvn;
	uint16_t reserved;
	__be16  num_vlan;
};

/**
 * struct batadv_tvlv_tt_vlan_data - vlan specific tt data propagated through
 *  the tt tvlv container
 * @crc: crc32 checksum of the entries belonging to this vlan
 * @vid: vlan identifier
 * @reserved: unused, useful for alignment purposes
 */
struct batadv_tvlv_tt_vlan_data {
	__be32	crc;
	__be16	vid;
	uint16_t reserved;
};

/**