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

Commit bc7892ba authored by Mike Rapoport's avatar Mike Rapoport Committed by Stephen Hemminger
Browse files

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: default avatarMike Rapoport <mike.rapoport@ravellosystems.com>
Signed-off-by: default avatarStephen Hemminger <stephen@networkplumber.org>
parent f0b074be
Loading
Loading
Loading
Loading
+40 −4
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ struct vxlan_rdst {
	u32			 remote_vni;
	u32			 remote_ifindex;
	struct list_head	 list;
	struct rcu_head		 rcu;
};

/* Forwarding table entry */
@@ -496,6 +497,12 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
	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)
{
	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_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);
	f = vxlan_find_mac(vxlan, addr);
	if (f) {
		vxlan_fdb_destroy(vxlan, f);
	if (!f)
		goto out;

	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);

	return err;