Commit a76d1ca2 authored by Petr Machata's avatar Petr Machata Committed by David S. Miller
Browse files

vxlan: Split vxlan_fdb_update() in two



In order to make it easier to implement rollbacks after FDB update
vetoing, separate the FDB update code to two parts: one that deals with
updates of existing FDB entries, and one that creates new entries.

Signed-off-by: default avatarPetr Machata <petrm@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c2b200e0
Loading
Loading
Loading
Loading
+97 −61
Original line number Diff line number Diff line
@@ -855,30 +855,21 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
	call_rcu(&f->rcu, vxlan_fdb_free);
}

/* Add new entry to forwarding table -- assumes lock held */
static int vxlan_fdb_update(struct vxlan_dev *vxlan,
			    const u8 *mac, union vxlan_addr *ip,
static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
				     union vxlan_addr *ip,
				     __u16 state, __u16 flags,
			    __be16 port, __be32 src_vni, __be32 vni,
				     __be16 port, __be32 vni,
				     __u32 ifindex, __u16 ndm_flags,
				     struct vxlan_fdb *f,
				     bool swdev_notify)
{
	__u16 fdb_flags = (ndm_flags & ~NTF_USE);
	struct vxlan_rdst *rd = NULL;
	struct vxlan_fdb *f;
	int notify = 0;
	int rc;

	f = __vxlan_find_mac(vxlan, mac, src_vni);
	if (f) {
		if (flags & NLM_F_EXCL) {
			netdev_dbg(vxlan->dev,
				   "lost race to create %pM\n", mac);
			return -EEXIST;
		}

		/* Do not allow an externally learned entry to take over an
		 * entry added by the user.
	/* Do not allow an externally learned entry to take over an entry added
	 * by the user.
	 */
	if (!(fdb_flags & NTF_EXT_LEARNED) ||
	    !(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
@@ -898,11 +889,13 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
		/* Only change unicasts */
		if (!(is_multicast_ether_addr(f->eth_addr) ||
		      is_zero_ether_addr(f->eth_addr))) {
				notify |= vxlan_fdb_replace(f, ip, port, vni,
			rc = vxlan_fdb_replace(f, ip, port, vni,
					       ifindex);
			} else
			notify |= rc;
		} else {
			return -EOPNOTSUPP;
		}
	}
	if ((flags & NLM_F_APPEND) &&
	    (is_multicast_ether_addr(f->eth_addr) ||
	     is_zero_ether_addr(f->eth_addr))) {
@@ -915,9 +908,27 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,

	if (ndm_flags & NTF_USE)
		f->used = jiffies;
	} else {
		if (!(flags & NLM_F_CREATE))
			return -ENOENT;

	if (notify) {
		if (rd == NULL)
			rd = first_remote_rtnl(f);

		vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify);
	}

	return 0;
}

static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
				   const u8 *mac, union vxlan_addr *ip,
				   __u16 state, __u16 flags,
				   __be16 port, __be32 src_vni, __be32 vni,
				   __u32 ifindex, __u16 ndm_flags,
				   bool swdev_notify)
{
	__u16 fdb_flags = (ndm_flags & ~NTF_USE);
	struct vxlan_fdb *f;
	int rc;

	/* Disallow replace to add a multicast entry */
	if ((flags & NLM_F_REPLACE) &&
@@ -929,16 +940,41 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
			      vni, ifindex, fdb_flags, &f);
	if (rc < 0)
		return rc;
		notify = 1;

	vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
			 swdev_notify);
	return 0;
}

	if (notify) {
		if (rd == NULL)
			rd = first_remote_rtnl(f);
		vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify);
/* Add new entry to forwarding table -- assumes lock held */
static int vxlan_fdb_update(struct vxlan_dev *vxlan,
			    const u8 *mac, union vxlan_addr *ip,
			    __u16 state, __u16 flags,
			    __be16 port, __be32 src_vni, __be32 vni,
			    __u32 ifindex, __u16 ndm_flags,
			    bool swdev_notify)
{
	struct vxlan_fdb *f;

	f = __vxlan_find_mac(vxlan, mac, src_vni);
	if (f) {
		if (flags & NLM_F_EXCL) {
			netdev_dbg(vxlan->dev,
				   "lost race to create %pM\n", mac);
			return -EEXIST;
		}

	return 0;
		return vxlan_fdb_update_existing(vxlan, ip, state, flags, port,
						 vni, ifindex, ndm_flags, f,
						 swdev_notify);
	} else {
		if (!(flags & NLM_F_CREATE))
			return -ENOENT;

		return vxlan_fdb_update_create(vxlan, mac, ip, state, flags,
					       port, src_vni, vni, ifindex,
					       ndm_flags, swdev_notify);
	}
}

static void vxlan_dst_free(struct rcu_head *head)