Skip to content

Commit

Permalink
rocker: do not make neighbour entry changes when preparing transactions
Browse files Browse the repository at this point in the history
rocker_port_ipv4_nh() and in turn rocker_port_ipv4_neigh() may be
be called with trans == SWITCHDEV_TRANS_PREPARE and then
trans == SWITCHDEV_TRANS_COMMIT from switchdev_port_obj_set() via
fib_table_insert().

The first time that rocker_port_ipv4_nh() is called, with
trans == SWITCHDEV_TRANS_PREPARE, _rocker_neigh_add() adds a new entry to
the neigh table.

And the second time  rocker_port_ipv4_nh() is called, with
trans == SWITCHDEV_TRANS_COMMIT, that entry is found. This causes
rocker_port_ipv4_nh() to believe it is not adding an entry and thus it
frees "entry", which is still present in rocker driver's neigh table.

This problem does not appear to affect deletion as my analysis is that
deletion is always performed with trans == SWITCHDEV_TRANS_NONE.

For completeness _rocker_neigh_{add,del,prepare} are updated not to
manipulate fib table entries if trans == SWITCHDEV_TRANS_PREPARE.

Fixes: c4f2032 ("rocker: support prepare-commit transaction model")
Reported-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Scott Feldman <sfeldma@gmail.com>
Acked-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Simon Horman authored and David S. Miller committed May 21, 2015
1 parent 42e9488 commit 550ecc9
Showing 1 changed file with 13 additions and 6 deletions.
19 changes: 13 additions & 6 deletions drivers/net/ethernet/rocker/rocker.c
Original file line number Diff line number Diff line change
Expand Up @@ -2909,9 +2909,13 @@ static struct rocker_neigh_tbl_entry *
}

static void _rocker_neigh_add(struct rocker *rocker,
enum switchdev_trans trans,
struct rocker_neigh_tbl_entry *entry)
{
entry->index = rocker->neigh_tbl_next_index++;
entry->index = rocker->neigh_tbl_next_index;
if (trans == SWITCHDEV_TRANS_PREPARE)
return;
rocker->neigh_tbl_next_index++;
entry->ref_count++;
hash_add(rocker->neigh_tbl, &entry->entry,
be32_to_cpu(entry->ip_addr));
Expand All @@ -2921,19 +2925,22 @@ static void _rocker_neigh_del(struct rocker_port *rocker_port,
enum switchdev_trans trans,
struct rocker_neigh_tbl_entry *entry)
{
if (trans == SWITCHDEV_TRANS_PREPARE)
return;
if (--entry->ref_count == 0) {
hash_del(&entry->entry);
rocker_port_kfree(rocker_port, trans, entry);
}
}

static void _rocker_neigh_update(struct rocker_neigh_tbl_entry *entry,
enum switchdev_trans trans,
u8 *eth_dst, bool ttl_check)
{
if (eth_dst) {
ether_addr_copy(entry->eth_dst, eth_dst);
entry->ttl_check = ttl_check;
} else {
} else if (trans != SWITCHDEV_TRANS_PREPARE) {
entry->ref_count++;
}
}
Expand Down Expand Up @@ -2973,12 +2980,12 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
entry->dev = rocker_port->dev;
ether_addr_copy(entry->eth_dst, eth_dst);
entry->ttl_check = true;
_rocker_neigh_add(rocker, entry);
_rocker_neigh_add(rocker, trans, entry);
} else if (removing) {
memcpy(entry, found, sizeof(*entry));
_rocker_neigh_del(rocker_port, trans, found);
} else if (updating) {
_rocker_neigh_update(found, eth_dst, true);
_rocker_neigh_update(found, trans, eth_dst, true);
memcpy(entry, found, sizeof(*entry));
} else {
err = -ENOENT;
Expand Down Expand Up @@ -3089,13 +3096,13 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port,
if (adding) {
entry->ip_addr = ip_addr;
entry->dev = rocker_port->dev;
_rocker_neigh_add(rocker, entry);
_rocker_neigh_add(rocker, trans, entry);
*index = entry->index;
resolved = false;
} else if (removing) {
_rocker_neigh_del(rocker_port, trans, found);
} else if (updating) {
_rocker_neigh_update(found, NULL, false);
_rocker_neigh_update(found, trans, NULL, false);
resolved = !is_zero_ether_addr(found->eth_dst);
} else {
err = -ENOENT;
Expand Down

0 comments on commit 550ecc9

Please sign in to comment.