diff options
author | Mike Rapoport <mike.rapoport@ravellosystems.com> | 2013-06-25 09:01:54 -0400 |
---|---|---|
committer | Stephen Hemminger <stephen@networkplumber.org> | 2013-06-25 12:31:38 -0400 |
commit | bc7892ba39992c6d645e906f1d52a626395b4b11 (patch) | |
tree | 846e364576bd91c051db6d0e234f81c086c69e39 /drivers/net/vxlan.c | |
parent | f0b074be7b61a800e39053d73dabf850649c1c8f (diff) |
vxlan: allow removal of single destination from fdb entry
When the last item is deleted from the remote destinations list, the
fdb entry is destroyed.
Signed-off-by: Mike Rapoport <mike.rapoport@ravellosystems.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Diffstat (limited to 'drivers/net/vxlan.c')
-rw-r--r-- | drivers/net/vxlan.c | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index ee7cc71e57fd..c1825201f9e2 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -105,6 +105,7 @@ struct vxlan_rdst { | |||
105 | u32 remote_vni; | 105 | u32 remote_vni; |
106 | u32 remote_ifindex; | 106 | u32 remote_ifindex; |
107 | struct list_head list; | 107 | struct list_head list; |
108 | struct rcu_head rcu; | ||
108 | }; | 109 | }; |
109 | 110 | ||
110 | /* Forwarding table entry */ | 111 | /* Forwarding table entry */ |
@@ -496,6 +497,12 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, | |||
496 | return 0; | 497 | return 0; |
497 | } | 498 | } |
498 | 499 | ||
500 | static void vxlan_fdb_free_rdst(struct rcu_head *head) | ||
501 | { | ||
502 | struct vxlan_rdst *rd = container_of(head, struct vxlan_rdst, rcu); | ||
503 | kfree(rd); | ||
504 | } | ||
505 | |||
499 | static void vxlan_fdb_free(struct rcu_head *head) | 506 | static void vxlan_fdb_free(struct rcu_head *head) |
500 | { | 507 | { |
501 | struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu); | 508 | struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu); |
@@ -605,14 +612,43 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], | |||
605 | { | 612 | { |
606 | struct vxlan_dev *vxlan = netdev_priv(dev); | 613 | struct vxlan_dev *vxlan = netdev_priv(dev); |
607 | struct vxlan_fdb *f; | 614 | struct vxlan_fdb *f; |
608 | int err = -ENOENT; | 615 | struct vxlan_rdst *rd = NULL; |
616 | __be32 ip; | ||
617 | __be16 port; | ||
618 | u32 vni, ifindex; | ||
619 | int err; | ||
620 | |||
621 | err = vxlan_fdb_parse(tb, vxlan, &ip, &port, &vni, &ifindex); | ||
622 | if (err) | ||
623 | return err; | ||
624 | |||
625 | err = -ENOENT; | ||
609 | 626 | ||
610 | spin_lock_bh(&vxlan->hash_lock); | 627 | spin_lock_bh(&vxlan->hash_lock); |
611 | f = vxlan_find_mac(vxlan, addr); | 628 | f = vxlan_find_mac(vxlan, addr); |
612 | if (f) { | 629 | if (!f) |
613 | vxlan_fdb_destroy(vxlan, f); | 630 | goto out; |
614 | err = 0; | 631 | |
632 | if (ip != htonl(INADDR_ANY)) { | ||
633 | rd = vxlan_fdb_find_rdst(f, ip, port, vni, ifindex); | ||
634 | if (!rd) | ||
635 | goto out; | ||
636 | } | ||
637 | |||
638 | err = 0; | ||
639 | |||
640 | /* remove a destination if it's not the only one on the list, | ||
641 | * otherwise destroy the fdb entry | ||
642 | */ | ||
643 | if (rd && !list_is_singular(&f->remotes)) { | ||
644 | list_del_rcu(&rd->list); | ||
645 | call_rcu(&rd->rcu, vxlan_fdb_free_rdst); | ||
646 | goto out; | ||
615 | } | 647 | } |
648 | |||
649 | vxlan_fdb_destroy(vxlan, f); | ||
650 | |||
651 | out: | ||
616 | spin_unlock_bh(&vxlan->hash_lock); | 652 | spin_unlock_bh(&vxlan->hash_lock); |
617 | 653 | ||
618 | return err; | 654 | return err; |