vxlan: allow removal of single destination from fdb entry

When the last item is deleted from the remote destinations list, the
fdb entry is destroyed.

Signed-off-by: Mike Rapoport <mike.rapoport@ravellosystems.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
This commit is contained in:
Mike Rapoport 2013-06-25 16:01:54 +03:00 committed by Stephen Hemminger
parent f0b074be7b
commit bc7892ba39

View file

@ -105,6 +105,7 @@ struct vxlan_rdst {
u32 remote_vni; u32 remote_vni;
u32 remote_ifindex; u32 remote_ifindex;
struct list_head list; struct list_head list;
struct rcu_head rcu;
}; };
/* Forwarding table entry */ /* Forwarding table entry */
@ -496,6 +497,12 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
return 0; return 0;
} }
static void vxlan_fdb_free_rdst(struct rcu_head *head)
{
struct vxlan_rdst *rd = container_of(head, struct vxlan_rdst, rcu);
kfree(rd);
}
static void vxlan_fdb_free(struct rcu_head *head) static void vxlan_fdb_free(struct rcu_head *head)
{ {
struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu); struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu);
@ -605,14 +612,43 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
{ {
struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_fdb *f; struct vxlan_fdb *f;
int err = -ENOENT; struct vxlan_rdst *rd = NULL;
__be32 ip;
__be16 port;
u32 vni, ifindex;
int err;
err = vxlan_fdb_parse(tb, vxlan, &ip, &port, &vni, &ifindex);
if (err)
return err;
err = -ENOENT;
spin_lock_bh(&vxlan->hash_lock); spin_lock_bh(&vxlan->hash_lock);
f = vxlan_find_mac(vxlan, addr); f = vxlan_find_mac(vxlan, addr);
if (f) { if (!f)
vxlan_fdb_destroy(vxlan, f); goto out;
err = 0;
if (ip != htonl(INADDR_ANY)) {
rd = vxlan_fdb_find_rdst(f, ip, port, vni, ifindex);
if (!rd)
goto out;
} }
err = 0;
/* remove a destination if it's not the only one on the list,
* otherwise destroy the fdb entry
*/
if (rd && !list_is_singular(&f->remotes)) {
list_del_rcu(&rd->list);
call_rcu(&rd->rcu, vxlan_fdb_free_rdst);
goto out;
}
vxlan_fdb_destroy(vxlan, f);
out:
spin_unlock_bh(&vxlan->hash_lock); spin_unlock_bh(&vxlan->hash_lock);
return err; return err;