diff options
| -rw-r--r-- | drivers/net/vxlan.c | 38 |
1 files changed, 21 insertions, 17 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 82355d5d155a..4dbb2ed85b97 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
| @@ -389,8 +389,8 @@ static inline size_t vxlan_nlmsg_size(void) | |||
| 389 | + nla_total_size(sizeof(struct nda_cacheinfo)); | 389 | + nla_total_size(sizeof(struct nda_cacheinfo)); |
| 390 | } | 390 | } |
| 391 | 391 | ||
| 392 | static void vxlan_fdb_notify(struct vxlan_dev *vxlan, | 392 | static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, |
| 393 | struct vxlan_fdb *fdb, int type) | 393 | struct vxlan_rdst *rd, int type) |
| 394 | { | 394 | { |
| 395 | struct net *net = dev_net(vxlan->dev); | 395 | struct net *net = dev_net(vxlan->dev); |
| 396 | struct sk_buff *skb; | 396 | struct sk_buff *skb; |
| @@ -400,8 +400,7 @@ static void vxlan_fdb_notify(struct vxlan_dev *vxlan, | |||
| 400 | if (skb == NULL) | 400 | if (skb == NULL) |
| 401 | goto errout; | 401 | goto errout; |
| 402 | 402 | ||
| 403 | err = vxlan_fdb_info(skb, vxlan, fdb, 0, 0, type, 0, | 403 | err = vxlan_fdb_info(skb, vxlan, fdb, 0, 0, type, 0, rd); |
| 404 | first_remote_rtnl(fdb)); | ||
| 405 | if (err < 0) { | 404 | if (err < 0) { |
| 406 | /* -EMSGSIZE implies BUG in vxlan_nlmsg_size() */ | 405 | /* -EMSGSIZE implies BUG in vxlan_nlmsg_size() */ |
| 407 | WARN_ON(err == -EMSGSIZE); | 406 | WARN_ON(err == -EMSGSIZE); |
| @@ -427,10 +426,7 @@ static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa) | |||
| 427 | .remote_vni = VXLAN_N_VID, | 426 | .remote_vni = VXLAN_N_VID, |
| 428 | }; | 427 | }; |
| 429 | 428 | ||
| 430 | INIT_LIST_HEAD(&f.remotes); | 429 | vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH); |
| 431 | list_add_rcu(&remote.list, &f.remotes); | ||
| 432 | |||
| 433 | vxlan_fdb_notify(vxlan, &f, RTM_GETNEIGH); | ||
| 434 | } | 430 | } |
| 435 | 431 | ||
| 436 | static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN]) | 432 | static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN]) |
| @@ -438,11 +434,11 @@ static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN]) | |||
| 438 | struct vxlan_fdb f = { | 434 | struct vxlan_fdb f = { |
| 439 | .state = NUD_STALE, | 435 | .state = NUD_STALE, |
| 440 | }; | 436 | }; |
| 437 | struct vxlan_rdst remote = { }; | ||
| 441 | 438 | ||
| 442 | INIT_LIST_HEAD(&f.remotes); | ||
| 443 | memcpy(f.eth_addr, eth_addr, ETH_ALEN); | 439 | memcpy(f.eth_addr, eth_addr, ETH_ALEN); |
| 444 | 440 | ||
| 445 | vxlan_fdb_notify(vxlan, &f, RTM_GETNEIGH); | 441 | vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH); |
| 446 | } | 442 | } |
| 447 | 443 | ||
| 448 | /* Hash Ethernet address */ | 444 | /* Hash Ethernet address */ |
| @@ -533,7 +529,8 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f, | |||
| 533 | 529 | ||
| 534 | /* Add/update destinations for multicast */ | 530 | /* Add/update destinations for multicast */ |
| 535 | static int vxlan_fdb_append(struct vxlan_fdb *f, | 531 | static int vxlan_fdb_append(struct vxlan_fdb *f, |
| 536 | union vxlan_addr *ip, __be16 port, __u32 vni, __u32 ifindex) | 532 | union vxlan_addr *ip, __be16 port, __u32 vni, |
| 533 | __u32 ifindex, struct vxlan_rdst **rdp) | ||
| 537 | { | 534 | { |
| 538 | struct vxlan_rdst *rd; | 535 | struct vxlan_rdst *rd; |
| 539 | 536 | ||
| @@ -551,6 +548,7 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, | |||
| 551 | 548 | ||
| 552 | list_add_tail_rcu(&rd->list, &f->remotes); | 549 | list_add_tail_rcu(&rd->list, &f->remotes); |
| 553 | 550 | ||
| 551 | *rdp = rd; | ||
| 554 | return 1; | 552 | return 1; |
| 555 | } | 553 | } |
| 556 | 554 | ||
| @@ -690,6 +688,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, | |||
| 690 | __be16 port, __u32 vni, __u32 ifindex, | 688 | __be16 port, __u32 vni, __u32 ifindex, |
| 691 | __u8 ndm_flags) | 689 | __u8 ndm_flags) |
| 692 | { | 690 | { |
| 691 | struct vxlan_rdst *rd = NULL; | ||
| 693 | struct vxlan_fdb *f; | 692 | struct vxlan_fdb *f; |
| 694 | int notify = 0; | 693 | int notify = 0; |
| 695 | 694 | ||
| @@ -726,7 +725,8 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, | |||
| 726 | if ((flags & NLM_F_APPEND) && | 725 | if ((flags & NLM_F_APPEND) && |
| 727 | (is_multicast_ether_addr(f->eth_addr) || | 726 | (is_multicast_ether_addr(f->eth_addr) || |
| 728 | is_zero_ether_addr(f->eth_addr))) { | 727 | is_zero_ether_addr(f->eth_addr))) { |
| 729 | int rc = vxlan_fdb_append(f, ip, port, vni, ifindex); | 728 | int rc = vxlan_fdb_append(f, ip, port, vni, ifindex, |
| 729 | &rd); | ||
| 730 | 730 | ||
| 731 | if (rc < 0) | 731 | if (rc < 0) |
| 732 | return rc; | 732 | return rc; |
| @@ -756,15 +756,18 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, | |||
| 756 | INIT_LIST_HEAD(&f->remotes); | 756 | INIT_LIST_HEAD(&f->remotes); |
| 757 | memcpy(f->eth_addr, mac, ETH_ALEN); | 757 | memcpy(f->eth_addr, mac, ETH_ALEN); |
| 758 | 758 | ||
| 759 | vxlan_fdb_append(f, ip, port, vni, ifindex); | 759 | vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); |
| 760 | 760 | ||
| 761 | ++vxlan->addrcnt; | 761 | ++vxlan->addrcnt; |
| 762 | hlist_add_head_rcu(&f->hlist, | 762 | hlist_add_head_rcu(&f->hlist, |
| 763 | vxlan_fdb_head(vxlan, mac)); | 763 | vxlan_fdb_head(vxlan, mac)); |
| 764 | } | 764 | } |
| 765 | 765 | ||
| 766 | if (notify) | 766 | if (notify) { |
| 767 | vxlan_fdb_notify(vxlan, f, RTM_NEWNEIGH); | 767 | if (rd == NULL) |
| 768 | rd = first_remote_rtnl(f); | ||
| 769 | vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH); | ||
| 770 | } | ||
| 768 | 771 | ||
| 769 | return 0; | 772 | return 0; |
| 770 | } | 773 | } |
| @@ -785,7 +788,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f) | |||
| 785 | "delete %pM\n", f->eth_addr); | 788 | "delete %pM\n", f->eth_addr); |
| 786 | 789 | ||
| 787 | --vxlan->addrcnt; | 790 | --vxlan->addrcnt; |
| 788 | vxlan_fdb_notify(vxlan, f, RTM_DELNEIGH); | 791 | vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH); |
| 789 | 792 | ||
| 790 | hlist_del_rcu(&f->hlist); | 793 | hlist_del_rcu(&f->hlist); |
| 791 | call_rcu(&f->rcu, vxlan_fdb_free); | 794 | call_rcu(&f->rcu, vxlan_fdb_free); |
| @@ -919,6 +922,7 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], | |||
| 919 | */ | 922 | */ |
| 920 | if (rd && !list_is_singular(&f->remotes)) { | 923 | if (rd && !list_is_singular(&f->remotes)) { |
| 921 | list_del_rcu(&rd->list); | 924 | list_del_rcu(&rd->list); |
| 925 | vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH); | ||
| 922 | kfree_rcu(rd, rcu); | 926 | kfree_rcu(rd, rcu); |
| 923 | goto out; | 927 | goto out; |
| 924 | } | 928 | } |
| @@ -993,7 +997,7 @@ static bool vxlan_snoop(struct net_device *dev, | |||
| 993 | 997 | ||
| 994 | rdst->remote_ip = *src_ip; | 998 | rdst->remote_ip = *src_ip; |
| 995 | f->updated = jiffies; | 999 | f->updated = jiffies; |
| 996 | vxlan_fdb_notify(vxlan, f, RTM_NEWNEIGH); | 1000 | vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH); |
| 997 | } else { | 1001 | } else { |
| 998 | /* learned new entry */ | 1002 | /* learned new entry */ |
| 999 | spin_lock(&vxlan->hash_lock); | 1003 | spin_lock(&vxlan->hash_lock); |
