diff options
author | Cong Wang <amwang@redhat.com> | 2012-12-11 17:23:08 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-12 13:02:30 -0500 |
commit | cfd567543590f71ca0af397437e2554f9756d750 (patch) | |
tree | b21b43cc137cb00386bd2d0d1533c9742224a050 /net/bridge/br_multicast.c | |
parent | 37a393bc4932d7bac360f40064aaafc01ab44901 (diff) |
bridge: add support of adding and deleting mdb entries
This patch implents adding/deleting mdb entries via netlink.
Currently all entries are temp, we probably need a flag to distinguish
permanent entries too.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Stephen Hemminger <shemminger@vyatta.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_multicast.c')
-rw-r--r-- | net/bridge/br_multicast.c | 55 |
1 files changed, 26 insertions, 29 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index d929586ce39e..977c3ee02e65 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -27,27 +27,14 @@ | |||
27 | #if IS_ENABLED(CONFIG_IPV6) | 27 | #if IS_ENABLED(CONFIG_IPV6) |
28 | #include <net/ipv6.h> | 28 | #include <net/ipv6.h> |
29 | #include <net/mld.h> | 29 | #include <net/mld.h> |
30 | #include <net/addrconf.h> | ||
31 | #include <net/ip6_checksum.h> | 30 | #include <net/ip6_checksum.h> |
32 | #endif | 31 | #endif |
33 | 32 | ||
34 | #include "br_private.h" | 33 | #include "br_private.h" |
35 | 34 | ||
36 | #define mlock_dereference(X, br) \ | ||
37 | rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock)) | ||
38 | |||
39 | static void br_multicast_start_querier(struct net_bridge *br); | 35 | static void br_multicast_start_querier(struct net_bridge *br); |
40 | unsigned int br_mdb_rehash_seq; | 36 | unsigned int br_mdb_rehash_seq; |
41 | 37 | ||
42 | #if IS_ENABLED(CONFIG_IPV6) | ||
43 | static inline int ipv6_is_transient_multicast(const struct in6_addr *addr) | ||
44 | { | ||
45 | if (ipv6_addr_is_multicast(addr) && IPV6_ADDR_MC_FLAG_TRANSIENT(addr)) | ||
46 | return 1; | ||
47 | return 0; | ||
48 | } | ||
49 | #endif | ||
50 | |||
51 | static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b) | 38 | static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b) |
52 | { | 39 | { |
53 | if (a->proto != b->proto) | 40 | if (a->proto != b->proto) |
@@ -104,8 +91,8 @@ static struct net_bridge_mdb_entry *__br_mdb_ip_get( | |||
104 | return NULL; | 91 | return NULL; |
105 | } | 92 | } |
106 | 93 | ||
107 | static struct net_bridge_mdb_entry *br_mdb_ip_get( | 94 | struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge_mdb_htable *mdb, |
108 | struct net_bridge_mdb_htable *mdb, struct br_ip *dst) | 95 | struct br_ip *dst) |
109 | { | 96 | { |
110 | if (!mdb) | 97 | if (!mdb) |
111 | return NULL; | 98 | return NULL; |
@@ -208,7 +195,7 @@ static int br_mdb_copy(struct net_bridge_mdb_htable *new, | |||
208 | return maxlen > elasticity ? -EINVAL : 0; | 195 | return maxlen > elasticity ? -EINVAL : 0; |
209 | } | 196 | } |
210 | 197 | ||
211 | static void br_multicast_free_pg(struct rcu_head *head) | 198 | void br_multicast_free_pg(struct rcu_head *head) |
212 | { | 199 | { |
213 | struct net_bridge_port_group *p = | 200 | struct net_bridge_port_group *p = |
214 | container_of(head, struct net_bridge_port_group, rcu); | 201 | container_of(head, struct net_bridge_port_group, rcu); |
@@ -584,9 +571,8 @@ err: | |||
584 | return mp; | 571 | return mp; |
585 | } | 572 | } |
586 | 573 | ||
587 | static struct net_bridge_mdb_entry *br_multicast_new_group( | 574 | struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br, |
588 | struct net_bridge *br, struct net_bridge_port *port, | 575 | struct net_bridge_port *port, struct br_ip *group) |
589 | struct br_ip *group) | ||
590 | { | 576 | { |
591 | struct net_bridge_mdb_htable *mdb; | 577 | struct net_bridge_mdb_htable *mdb; |
592 | struct net_bridge_mdb_entry *mp; | 578 | struct net_bridge_mdb_entry *mp; |
@@ -633,6 +619,26 @@ out: | |||
633 | return mp; | 619 | return mp; |
634 | } | 620 | } |
635 | 621 | ||
622 | struct net_bridge_port_group *br_multicast_new_port_group( | ||
623 | struct net_bridge_port *port, | ||
624 | struct br_ip *group, | ||
625 | struct net_bridge_port_group *next) | ||
626 | { | ||
627 | struct net_bridge_port_group *p; | ||
628 | |||
629 | p = kzalloc(sizeof(*p), GFP_ATOMIC); | ||
630 | if (unlikely(!p)) | ||
631 | return NULL; | ||
632 | |||
633 | p->addr = *group; | ||
634 | p->port = port; | ||
635 | p->next = next; | ||
636 | hlist_add_head(&p->mglist, &port->mglist); | ||
637 | setup_timer(&p->timer, br_multicast_port_group_expired, | ||
638 | (unsigned long)p); | ||
639 | return p; | ||
640 | } | ||
641 | |||
636 | static int br_multicast_add_group(struct net_bridge *br, | 642 | static int br_multicast_add_group(struct net_bridge *br, |
637 | struct net_bridge_port *port, | 643 | struct net_bridge_port *port, |
638 | struct br_ip *group) | 644 | struct br_ip *group) |
@@ -668,18 +674,9 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
668 | break; | 674 | break; |
669 | } | 675 | } |
670 | 676 | ||
671 | p = kzalloc(sizeof(*p), GFP_ATOMIC); | 677 | p = br_multicast_new_port_group(port, group, *pp); |
672 | err = -ENOMEM; | ||
673 | if (unlikely(!p)) | 678 | if (unlikely(!p)) |
674 | goto err; | 679 | goto err; |
675 | |||
676 | p->addr = *group; | ||
677 | p->port = port; | ||
678 | p->next = *pp; | ||
679 | hlist_add_head(&p->mglist, &port->mglist); | ||
680 | setup_timer(&p->timer, br_multicast_port_group_expired, | ||
681 | (unsigned long)p); | ||
682 | |||
683 | rcu_assign_pointer(*pp, p); | 680 | rcu_assign_pointer(*pp, p); |
684 | br_mdb_notify(br->dev, port, group, RTM_NEWMDB); | 681 | br_mdb_notify(br->dev, port, group, RTM_NEWMDB); |
685 | 682 | ||