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,92 +855,128 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, ...@@ -855,92 +855,128 @@ 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 vni,
__be16 port, __be32 src_vni, __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, if (!(fdb_flags & NTF_EXT_LEARNED) ||
"lost race to create %pM\n", mac); !(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
return -EEXIST; if (f->state != state) {
} f->state = state;
f->updated = jiffies;
/* Do not allow an externally learned entry to take over an notify = 1;
* entry added by the user.
*/
if (!(fdb_flags & NTF_EXT_LEARNED) ||
!(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
if (f->state != state) {
f->state = state;
f->updated = jiffies;
notify = 1;
}
if (f->flags != fdb_flags) {
f->flags = fdb_flags;
f->updated = jiffies;
notify = 1;
}
} }
if (f->flags != fdb_flags) {
if ((flags & NLM_F_REPLACE)) { f->flags = fdb_flags;
/* Only change unicasts */ f->updated = jiffies;
if (!(is_multicast_ether_addr(f->eth_addr) || notify = 1;
is_zero_ether_addr(f->eth_addr))) {
notify |= vxlan_fdb_replace(f, ip, port, vni,
ifindex);
} else
return -EOPNOTSUPP;
} }
if ((flags & NLM_F_APPEND) && }
(is_multicast_ether_addr(f->eth_addr) ||
is_zero_ether_addr(f->eth_addr))) {
rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
if (rc < 0) if ((flags & NLM_F_REPLACE)) {
return rc; /* Only change unicasts */
if (!(is_multicast_ether_addr(f->eth_addr) ||
is_zero_ether_addr(f->eth_addr))) {
rc = vxlan_fdb_replace(f, ip, port, vni,
ifindex);
notify |= rc; notify |= rc;
} } else {
if (ndm_flags & NTF_USE)
f->used = jiffies;
} else {
if (!(flags & NLM_F_CREATE))
return -ENOENT;
/* Disallow replace to add a multicast entry */
if ((flags & NLM_F_REPLACE) &&
(is_multicast_ether_addr(mac) || is_zero_ether_addr(mac)))
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
}
if ((flags & NLM_F_APPEND) &&
(is_multicast_ether_addr(f->eth_addr) ||
is_zero_ether_addr(f->eth_addr))) {
rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni,
vni, ifindex, fdb_flags, &f);
if (rc < 0) if (rc < 0)
return rc; return rc;
notify = 1; notify |= rc;
} }
if (ndm_flags & NTF_USE)
f->used = jiffies;
if (notify) { if (notify) {
if (rd == NULL) if (rd == NULL)
rd = first_remote_rtnl(f); rd = first_remote_rtnl(f);
vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify); vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify);
} }
return 0; 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) &&
(is_multicast_ether_addr(mac) || is_zero_ether_addr(mac)))
return -EOPNOTSUPP;
netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni,
vni, ifindex, fdb_flags, &f);
if (rc < 0)
return rc;
vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
swdev_notify);
return 0;
}
/* 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 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)
{ {
struct vxlan_rdst *rd = container_of(head, struct vxlan_rdst, rcu); struct vxlan_rdst *rd = container_of(head, struct vxlan_rdst, rcu);
......
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