Skip to content

Commit

Permalink
vxlan: ensure to advertise the right fdb remote
Browse files Browse the repository at this point in the history
The goal of this patch is to fix rtnelink notification. The main problem was
about notification for fdb entry with more than one remote. Before the patch,
when a remote was added to an existing fdb entry, the kernel advertised the
first remote instead of the added one. Also when a remote was removed from a fdb
entry with several remotes, the deleted remote was not advertised.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
NicolasDichtel authored and davem330 committed Apr 23, 2014
1 parent 6a11974 commit 9e4b93f
Showing 1 changed file with 21 additions and 17 deletions.
38 changes: 21 additions & 17 deletions drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,8 @@ static inline size_t vxlan_nlmsg_size(void)
+ nla_total_size(sizeof(struct nda_cacheinfo));
}

static void vxlan_fdb_notify(struct vxlan_dev *vxlan,
struct vxlan_fdb *fdb, int type)
static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
struct vxlan_rdst *rd, int type)
{
struct net *net = dev_net(vxlan->dev);
struct sk_buff *skb;
Expand All @@ -400,8 +400,7 @@ static void vxlan_fdb_notify(struct vxlan_dev *vxlan,
if (skb == NULL)
goto errout;

err = vxlan_fdb_info(skb, vxlan, fdb, 0, 0, type, 0,
first_remote_rtnl(fdb));
err = vxlan_fdb_info(skb, vxlan, fdb, 0, 0, type, 0, rd);
if (err < 0) {
/* -EMSGSIZE implies BUG in vxlan_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
Expand All @@ -427,22 +426,19 @@ static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa)
.remote_vni = VXLAN_N_VID,
};

INIT_LIST_HEAD(&f.remotes);
list_add_rcu(&remote.list, &f.remotes);

vxlan_fdb_notify(vxlan, &f, RTM_GETNEIGH);
vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH);
}

static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN])
{
struct vxlan_fdb f = {
.state = NUD_STALE,
};
struct vxlan_rdst remote = { };

INIT_LIST_HEAD(&f.remotes);
memcpy(f.eth_addr, eth_addr, ETH_ALEN);

vxlan_fdb_notify(vxlan, &f, RTM_GETNEIGH);
vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH);
}

/* Hash Ethernet address */
Expand Down Expand Up @@ -533,7 +529,8 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,

/* Add/update destinations for multicast */
static int vxlan_fdb_append(struct vxlan_fdb *f,
union vxlan_addr *ip, __be16 port, __u32 vni, __u32 ifindex)
union vxlan_addr *ip, __be16 port, __u32 vni,
__u32 ifindex, struct vxlan_rdst **rdp)
{
struct vxlan_rdst *rd;

Expand All @@ -551,6 +548,7 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,

list_add_tail_rcu(&rd->list, &f->remotes);

*rdp = rd;
return 1;
}

Expand Down Expand Up @@ -690,6 +688,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
__be16 port, __u32 vni, __u32 ifindex,
__u8 ndm_flags)
{
struct vxlan_rdst *rd = NULL;
struct vxlan_fdb *f;
int notify = 0;

Expand Down Expand Up @@ -726,7 +725,8 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
if ((flags & NLM_F_APPEND) &&
(is_multicast_ether_addr(f->eth_addr) ||
is_zero_ether_addr(f->eth_addr))) {
int rc = vxlan_fdb_append(f, ip, port, vni, ifindex);
int rc = vxlan_fdb_append(f, ip, port, vni, ifindex,
&rd);

if (rc < 0)
return rc;
Expand Down Expand Up @@ -756,15 +756,18 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
INIT_LIST_HEAD(&f->remotes);
memcpy(f->eth_addr, mac, ETH_ALEN);

vxlan_fdb_append(f, ip, port, vni, ifindex);
vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);

++vxlan->addrcnt;
hlist_add_head_rcu(&f->hlist,
vxlan_fdb_head(vxlan, mac));
}

if (notify)
vxlan_fdb_notify(vxlan, f, RTM_NEWNEIGH);
if (notify) {
if (rd == NULL)
rd = first_remote_rtnl(f);
vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH);
}

return 0;
}
Expand All @@ -785,7 +788,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f)
"delete %pM\n", f->eth_addr);

--vxlan->addrcnt;
vxlan_fdb_notify(vxlan, f, RTM_DELNEIGH);
vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH);

hlist_del_rcu(&f->hlist);
call_rcu(&f->rcu, vxlan_fdb_free);
Expand Down Expand Up @@ -919,6 +922,7 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
*/
if (rd && !list_is_singular(&f->remotes)) {
list_del_rcu(&rd->list);
vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH);
kfree_rcu(rd, rcu);
goto out;
}
Expand Down Expand Up @@ -993,7 +997,7 @@ static bool vxlan_snoop(struct net_device *dev,

rdst->remote_ip = *src_ip;
f->updated = jiffies;
vxlan_fdb_notify(vxlan, f, RTM_NEWNEIGH);
vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH);
} else {
/* learned new entry */
spin_lock(&vxlan->hash_lock);
Expand Down

0 comments on commit 9e4b93f

Please sign in to comment.