Skip to content

Commit

Permalink
batman-adv: make the TT CRC logic VLAN specific
Browse files Browse the repository at this point in the history
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: Antonio Quartulli <antonio@open-mesh.com>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
  • Loading branch information
ordex committed Oct 19, 2013
1 parent a70a9aa commit 7ea7b4a
Show file tree
Hide file tree
Showing 5 changed files with 730 additions and 157 deletions.
101 changes: 98 additions & 3 deletions net/batman-adv/originator.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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);
Expand All @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions net/batman-adv/originator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 15 additions & 3 deletions net/batman-adv/packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
__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;
__be32 crc;
};

/**
Expand Down
Loading

0 comments on commit 7ea7b4a

Please sign in to comment.