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

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
...@@ -855,30 +855,21 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, ...@@ -855,30 +855,21 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
call_rcu(&f->rcu, vxlan_fdb_free); call_rcu(&f->rcu, vxlan_fdb_free);
} }
/* Add new entry to forwarding table -- assumes lock held */ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
static int vxlan_fdb_update(struct vxlan_dev *vxlan, union vxlan_addr *ip,
const u8 *mac, union vxlan_addr *ip,
__u16 state, __u16 flags, __u16 state, __u16 flags,
__be16 port, __be32 src_vni, __be32 vni, __be16 port, __be32 vni,
__u32 ifindex, __u16 ndm_flags, __u32 ifindex, __u16 ndm_flags,
struct vxlan_fdb *f,
bool swdev_notify) bool swdev_notify)
{ {
__u16 fdb_flags = (ndm_flags & ~NTF_USE); __u16 fdb_flags = (ndm_flags & ~NTF_USE);
struct vxlan_rdst *rd = NULL; struct vxlan_rdst *rd = NULL;
struct vxlan_fdb *f;
int notify = 0; int notify = 0;
int rc; int rc;
f = __vxlan_find_mac(vxlan, mac, src_vni); /* Do not allow an externally learned entry to take over an entry added
if (f) { * by the user.
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.
*/ */
if (!(fdb_flags & NTF_EXT_LEARNED) || if (!(fdb_flags & NTF_EXT_LEARNED) ||
!(f->flags & NTF_VXLAN_ADDED_BY_USER)) { !(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
...@@ -898,11 +889,13 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, ...@@ -898,11 +889,13 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
/* Only change unicasts */ /* Only change unicasts */
if (!(is_multicast_ether_addr(f->eth_addr) || if (!(is_multicast_ether_addr(f->eth_addr) ||
is_zero_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); ifindex);
} else notify |= rc;
} else {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
}
if ((flags & NLM_F_APPEND) && if ((flags & NLM_F_APPEND) &&
(is_multicast_ether_addr(f->eth_addr) || (is_multicast_ether_addr(f->eth_addr) ||
is_zero_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, ...@@ -915,9 +908,27 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
if (ndm_flags & NTF_USE) if (ndm_flags & NTF_USE)
f->used = jiffies; f->used = jiffies;
} else {
if (!(flags & NLM_F_CREATE)) if (notify) {
return -ENOENT; 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 */ /* Disallow replace to add a multicast entry */
if ((flags & NLM_F_REPLACE) && if ((flags & NLM_F_REPLACE) &&
...@@ -929,16 +940,41 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, ...@@ -929,16 +940,41 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
vni, ifindex, fdb_flags, &f); vni, ifindex, fdb_flags, &f);
if (rc < 0) if (rc < 0)
return rc; return rc;
notify = 1;
}
if (notify) { vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
if (rd == NULL) swdev_notify);
rd = first_remote_rtnl(f); return 0;
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) static void vxlan_dst_free(struct rcu_head *head)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment