From: Marek Lindner <lindner_marek@yahoo.de>
To: The list for a Better Approach To Mobile Ad-hoc Networking
<b.a.t.m.a.n@lists.open-mesh.org>
Subject: Re: [B.A.T.M.A.N.] [PATCHv5] batman-adv: make the TT CRC logic VLAN specific
Date: Thu, 4 Jul 2013 17:07:05 +0800 [thread overview]
Message-ID: <201307041707.05262.lindner_marek@yahoo.de> (raw)
In-Reply-To: <1372869216-2514-1-git-send-email-ordex@autistici.org>
On Thursday, July 04, 2013 00:33:36 Antonio Quartulli wrote:
> --- a/originator.c
> +++ b/originator.c
> @@ -44,6 +44,95 @@ 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 servin 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;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
> + if (!atomic_inc_not_zero(&vlan->refcount))
> + continue;
> +
> + if (vlan->vid != vid)
> + continue;
> +
> + rcu_read_unlock();
> +
> + return vlan;
> + }
> + rcu_read_unlock();
> +
> + return NULL;
> +}
Big memory leak here. First check the validity of the list item before
increasing its refcounter. Please also keep the return variable style similar
to other functions in the batman-adv code.
> +/**
> + * 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 */
> + list_for_each_entry(vlan, &orig_node->vlan_list, list) {
> + if (!atomic_inc_not_zero(&vlan->refcount))
> + continue;
> +
> + if (vlan->vid != vid)
> + continue;
> +
> + /* there is already an entry for this vid: return it */
> + goto out;
> + }
Same bug as above. Instead of duplicating the code, simply call
batadv_orig_node_vlan_get().
> +/**
> + * struct batadv_tvlv_tt_vlan_data - vlan specific tt data propagated
> through + * the tt vlv 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;
> };
How about turning the reserved field into "__be16" as well ?
> /**
> + * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send
> + * within a TT Response directed to another node
> + * @orig_node: originator for which the TT data has to be prepared
> + * @tt_data: uninitialised pointer to the address of the TVLV buffer
> + * @tt_len: space to reserve for the TT entries. If negative, this
> function will + * allocate as much space is needed for the full table
> + *
> + * Allocate the needed amount of memory for the entire TT TVLV and write
> its + * header made up by one tvlv_tt_data object and a series of
> tvlv_tt_vlan_data + * objects, one per active VLAN served by the
> originator node.
> + *
> + * Return the size of the allocated buffer or 0 in case of failure.
> + */
> +static uint16_t
> +batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
> + struct batadv_tvlv_tt_data **tt_data,
> + int32_t tt_len)
> +{
> + struct batadv_tvlv_tt_vlan_data *tt_vlan;
> + struct batadv_orig_node_vlan *vlan;
> + uint16_t num_vlan = 0, num_entries = 0;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
> + num_vlan++;
> + num_entries += atomic_read(&vlan->tt.num_entries);
> + }
> +
> + /* 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 += sizeof(**tt_data);
> + tt_len += sizeof(*tt_vlan) * num_vlan;
> +
> + *tt_data = kmalloc(tt_len, GFP_ATOMIC);
> + if (!*tt_data) {
> + tt_len = 0;
> + goto out;
> + }
> +
> + (*tt_data)->flags = BATADV_NO_FLAGS;
> + (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn);
> + (*tt_data)->num_vlan = htons(num_vlan);
> +
> + tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
> + list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
> + tt_vlan->vid = htons(vlan->vid);
> + tt_vlan->crc = htonl(vlan->tt.crc);
> +
> + tt_vlan++;
> + }
> +out:
> + rcu_read_unlock();
> + return tt_len;
> +}
Are you certain this is race condition free ? What if local or global node is
added while this function is running ?
> +/**
> * batadv_tt_tvlv_container_update - update the translation table tvlv
> container * after local tt changes have been committed
> * @bat_priv: the bat priv with all the soft interface information
> @@ -473,10 +679,11 @@ static void batadv_tt_tvlv_container_update(struct
> batadv_priv *bat_priv) struct batadv_tt_change_node *entry, *safe;
> struct batadv_tvlv_tt_data *tt_data;
> struct batadv_tvlv_tt_change *tt_change;
> - int tt_diff_len = 0, tt_change_len = 0;
> + int tt_diff_len, tt_change_len = 0;
> int tt_diff_entries_num = 0, tt_diff_entries_count = 0;
> + uint16_t tt_len, change_offset;
>
> - tt_diff_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes));
> + tt_diff_len = batadv_tt_len(atomic_read(&bat_priv->tt.local_changes));
>
> /* if we have too many changes for one packet don't send any
> * and wait for the tt table request which will be fragmented
> @@ -484,13 +691,16 @@ static void batadv_tt_tvlv_container_update(struct
> batadv_priv *bat_priv) if (tt_diff_len > bat_priv->soft_iface->mtu)
> tt_diff_len = 0;
>
> - tt_data = kzalloc(sizeof(*tt_data) + tt_diff_len, GFP_ATOMIC);
> - if (!tt_data)
> + tt_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
> + tt_diff_len);
> + if (!tt_len)
> return;
>
> tt_data->flags = BATADV_TT_OGM_DIFF;
> - tt_data->ttvn = atomic_read(&bat_priv->tt.vn);
> - tt_data->crc = htonl(bat_priv->tt.local_crc);
If you avoided this removal you could have one function instead of
batadv_tt_prepare_tvlv_local_data() and batadv_tt_prepare_tvlv_global_data()
doing basically the same thing.
> - tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1);
> + tt_change = (struct batadv_tvlv_tt_change *)((uint8_t *)tt_data +
> + change_offset);
David won't like that.
> - seq_printf(seq, " * %pM %4i [%c%c%c%c%c] %3u.%03u\n",
> + vlan = batadv_softif_vlan_get(bat_priv, vid);
> + if (!vlan) {
> + seq_printf(seq, "Cannot retrieve VLAN %d\n",
> + BATADV_PRINT_VID(vid));
> + continue;
> + }
> +
> + seq_printf(seq,
> + " * %pM %4i [%c%c%c%c%c] %3u.%03u (%#.8x)\n",
> tt_common_entry->addr,
> BATADV_PRINT_VID(tt_common_entry->vid),
> (tt_common_entry->flags &
> @@ -597,7 +818,8 @@ int batadv_tt_local_seq_print_text(struct seq_file
> *seq, void *offset) (tt_common_entry->flags &
> BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
> no_purge ? 0 : last_seen_secs,
> - no_purge ? 0 : last_seen_msecs);
> + no_purge ? 0 : last_seen_msecs,
> + vlan->tt.crc);
> }
> rcu_read_unlock();
> }
My feeling tells me we are missing batadv_softif_vlan_free_ref() call ?
> @@ -1070,35 +1292,49 @@ static void
> batadv_tt_global_print_entry(struct batadv_tt_global_entry
> *tt_global_entry, struct seq_file *seq)
> {
> - struct hlist_head *head;
> struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
> struct batadv_tt_common_entry *tt_common_entry;
> - uint16_t flags;
> + struct batadv_orig_node_vlan *vlan;
> + struct hlist_head *head;
> uint8_t last_ttvn;
> + uint16_t flags;
>
> tt_common_entry = &tt_global_entry->common;
> flags = tt_common_entry->flags;
> -
Now you try to remove empty lines ? :)
> best_entry = batadv_transtable_best_orig(tt_global_entry);
> if (best_entry) {
> + vlan = batadv_orig_node_vlan_get(best_entry->orig_node,
> + tt_common_entry->vid);
> + if (!vlan) {
> + seq_printf(seq,
> + " * Cannot retrieve VLAN %d for originator %pM\n",
> + BATADV_PRINT_VID(tt_common_entry->vid),
> + best_entry->orig_node->orig);
> + goto print_list;
> + }
> +
> last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
> seq_printf(seq,
> " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n",
> '*', tt_global_entry->common.addr,
> BATADV_PRINT_VID(tt_global_entry->common.vid),
> best_entry->ttvn, best_entry->orig_node->orig,
> - last_ttvn, best_entry->orig_node->tt_crc,
> + last_ttvn, vlan->tt.crc,
> (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
> (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
> (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
> }
How about a batadv_orig_node_vlan_free_ref() call ?
> +print_list:
> head = &tt_global_entry->orig_list;
>
> hlist_for_each_entry_rcu(orig_entry, head, list) {
> if (best_entry == orig_entry)
> continue;
>
> + vlan = batadv_orig_node_vlan_get(orig_entry->orig_node,
> + tt_common_entry->vid);
> +
> last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
> seq_printf(seq,
> " %c %pM %4d (%3u) via %pM (%3u) [%c%c%c]\n",
Another one ?
Cheers,
Marek
next prev parent reply other threads:[~2013-07-04 9:07 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-03 16:33 [B.A.T.M.A.N.] [PATCHv5] batman-adv: make the TT CRC logic VLAN specific Antonio Quartulli
2013-07-04 9:07 ` Marek Lindner [this message]
2013-07-09 17:22 ` Antonio Quartulli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201307041707.05262.lindner_marek@yahoo.de \
--to=lindner_marek@yahoo.de \
--cc=b.a.t.m.a.n@lists.open-mesh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox