summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>2016-06-28 10:57:06 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-30 06:18:24 -0400
commit1080ab95e3c7bdd77870e209aff83c763fdcf439 (patch)
tree16ffa738a90a36411886403ed92f5e1fef115486
parent80e73cc563c4359be809a03bcb8e7e28141a813a (diff)
net: bridge: add support for IGMP/MLD stats and export them via netlink
This patch adds stats support for the currently used IGMP/MLD types by the bridge. The stats are per-port (plus one stat per-bridge) and per-direction (RX/TX). The stats are exported via netlink via the new linkxstats API (RTM_GETSTATS). In order to minimize the performance impact, a new option is used to enable/disable the stats - multicast_stats_enabled, similar to the recent vlan stats. Also in order to avoid multiple IGMP/MLD type lookups and checks, we make use of the current "igmp" member of the bridge private skb->cb region to record the type on Rx (both host-generated and external packets pass by multicast_rcv()). We can do that since the igmp member was used as a boolean and all the valid IGMP/MLD types are positive values. The normal bridge fast-path is not affected at all, the only affected paths are the flooding ones and since we make use of the IGMP/MLD type, we can quickly determine if the packet should be counted using cache-hot data (cb's igmp member). We add counters for: * IGMP Queries * IGMP Leaves * IGMP v1/v2/v3 reports * MLD Queries * MLD Leaves * MLD v1/v2 reports These are invaluable when monitoring or debugging complex multicast setups with bridges. Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/if_bridge.h26
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--net/bridge/br_device.c10
-rw-r--r--net/bridge/br_forward.c13
-rw-r--r--net/bridge/br_if.c9
-rw-r--r--net/bridge/br_input.c3
-rw-r--r--net/bridge/br_multicast.c217
-rw-r--r--net/bridge/br_netlink.c91
-rw-r--r--net/bridge/br_private.h41
-rw-r--r--net/bridge/br_sysfs_br.c25
10 files changed, 390 insertions, 46 deletions
diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index 397d503fdedb..8304fe6f0561 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -247,8 +247,34 @@ enum {
247enum { 247enum {
248 BRIDGE_XSTATS_UNSPEC, 248 BRIDGE_XSTATS_UNSPEC,
249 BRIDGE_XSTATS_VLAN, 249 BRIDGE_XSTATS_VLAN,
250 BRIDGE_XSTATS_MCAST,
251 BRIDGE_XSTATS_PAD,
250 __BRIDGE_XSTATS_MAX 252 __BRIDGE_XSTATS_MAX
251}; 253};
252#define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1) 254#define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1)
253 255
256enum {
257 BR_MCAST_DIR_RX,
258 BR_MCAST_DIR_TX,
259 BR_MCAST_DIR_SIZE
260};
261
262/* IGMP/MLD statistics */
263struct br_mcast_stats {
264 __u64 igmp_queries[BR_MCAST_DIR_SIZE];
265 __u64 igmp_leaves[BR_MCAST_DIR_SIZE];
266 __u64 igmp_v1reports[BR_MCAST_DIR_SIZE];
267 __u64 igmp_v2reports[BR_MCAST_DIR_SIZE];
268 __u64 igmp_v3reports[BR_MCAST_DIR_SIZE];
269 __u64 igmp_parse_errors;
270
271 __u64 mld_queries[BR_MCAST_DIR_SIZE];
272 __u64 mld_leaves[BR_MCAST_DIR_SIZE];
273 __u64 mld_v1reports[BR_MCAST_DIR_SIZE];
274 __u64 mld_v2reports[BR_MCAST_DIR_SIZE];
275 __u64 mld_parse_errors;
276
277 __u64 mcast_bytes[BR_MCAST_DIR_SIZE];
278 __u64 mcast_packets[BR_MCAST_DIR_SIZE];
279};
254#endif /* _UAPI_LINUX_IF_BRIDGE_H */ 280#endif /* _UAPI_LINUX_IF_BRIDGE_H */
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index db2458ade81c..4285ac31e865 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -273,6 +273,7 @@ enum {
273 IFLA_BR_VLAN_DEFAULT_PVID, 273 IFLA_BR_VLAN_DEFAULT_PVID,
274 IFLA_BR_PAD, 274 IFLA_BR_PAD,
275 IFLA_BR_VLAN_STATS_ENABLED, 275 IFLA_BR_VLAN_STATS_ENABLED,
276 IFLA_BR_MCAST_STATS_ENABLED,
276 __IFLA_BR_MAX, 277 __IFLA_BR_MAX,
277}; 278};
278 279
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 2c8095a5d824..0c39e0f6da09 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -104,8 +104,16 @@ static int br_dev_init(struct net_device *dev)
104 return -ENOMEM; 104 return -ENOMEM;
105 105
106 err = br_vlan_init(br); 106 err = br_vlan_init(br);
107 if (err) 107 if (err) {
108 free_percpu(br->stats); 108 free_percpu(br->stats);
109 return err;
110 }
111
112 err = br_multicast_init_stats(br);
113 if (err) {
114 free_percpu(br->stats);
115 br_vlan_flush(br);
116 }
109 br_set_lockdep_class(dev); 117 br_set_lockdep_class(dev);
110 118
111 return err; 119 return err;
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index f47759f05b6d..6c196037d818 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -198,8 +198,10 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
198 struct sk_buff *skb), 198 struct sk_buff *skb),
199 bool unicast) 199 bool unicast)
200{ 200{
201 struct net_bridge_port *p; 201 u8 igmp_type = br_multicast_igmp_type(skb);
202 __be16 proto = skb->protocol;
202 struct net_bridge_port *prev; 203 struct net_bridge_port *prev;
204 struct net_bridge_port *p;
203 205
204 prev = NULL; 206 prev = NULL;
205 207
@@ -218,6 +220,9 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
218 prev = maybe_deliver(prev, p, skb, __packet_hook); 220 prev = maybe_deliver(prev, p, skb, __packet_hook);
219 if (IS_ERR(prev)) 221 if (IS_ERR(prev))
220 goto out; 222 goto out;
223 if (prev == p)
224 br_multicast_count(p->br, p, proto, igmp_type,
225 BR_MCAST_DIR_TX);
221 } 226 }
222 227
223 if (!prev) 228 if (!prev)
@@ -257,9 +262,12 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
257 struct sk_buff *skb)) 262 struct sk_buff *skb))
258{ 263{
259 struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; 264 struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
265 u8 igmp_type = br_multicast_igmp_type(skb);
260 struct net_bridge *br = netdev_priv(dev); 266 struct net_bridge *br = netdev_priv(dev);
261 struct net_bridge_port *prev = NULL; 267 struct net_bridge_port *prev = NULL;
262 struct net_bridge_port_group *p; 268 struct net_bridge_port_group *p;
269 __be16 proto = skb->protocol;
270
263 struct hlist_node *rp; 271 struct hlist_node *rp;
264 272
265 rp = rcu_dereference(hlist_first_rcu(&br->router_list)); 273 rp = rcu_dereference(hlist_first_rcu(&br->router_list));
@@ -277,6 +285,9 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
277 prev = maybe_deliver(prev, port, skb, __packet_hook); 285 prev = maybe_deliver(prev, port, skb, __packet_hook);
278 if (IS_ERR(prev)) 286 if (IS_ERR(prev))
279 goto out; 287 goto out;
288 if (prev == port)
289 br_multicast_count(port->br, port, proto, igmp_type,
290 BR_MCAST_DIR_TX);
280 291
281 if ((unsigned long)lport >= (unsigned long)port) 292 if ((unsigned long)lport >= (unsigned long)port)
282 p = rcu_dereference(p->next); 293 p = rcu_dereference(p->next);
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 8217aecf025b..f2fede05d32c 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -345,8 +345,8 @@ static int find_portno(struct net_bridge *br)
345static struct net_bridge_port *new_nbp(struct net_bridge *br, 345static struct net_bridge_port *new_nbp(struct net_bridge *br,
346 struct net_device *dev) 346 struct net_device *dev)
347{ 347{
348 int index;
349 struct net_bridge_port *p; 348 struct net_bridge_port *p;
349 int index, err;
350 350
351 index = find_portno(br); 351 index = find_portno(br);
352 if (index < 0) 352 if (index < 0)
@@ -366,7 +366,12 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
366 br_init_port(p); 366 br_init_port(p);
367 br_set_state(p, BR_STATE_DISABLED); 367 br_set_state(p, BR_STATE_DISABLED);
368 br_stp_port_timer_init(p); 368 br_stp_port_timer_init(p);
369 br_multicast_add_port(p); 369 err = br_multicast_add_port(p);
370 if (err) {
371 dev_put(dev);
372 kfree(p);
373 p = ERR_PTR(err);
374 }
370 375
371 return p; 376 return p;
372} 377}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 43d2cd862bc2..786602bc0567 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -60,6 +60,9 @@ static int br_pass_frame_up(struct sk_buff *skb)
60 skb = br_handle_vlan(br, vg, skb); 60 skb = br_handle_vlan(br, vg, skb);
61 if (!skb) 61 if (!skb)
62 return NET_RX_DROP; 62 return NET_RX_DROP;
63 /* update the multicast stats if the packet is IGMP/MLD */
64 br_multicast_count(br, NULL, skb->protocol, br_multicast_igmp_type(skb),
65 BR_MCAST_DIR_TX);
63 66
64 return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, 67 return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
65 dev_net(indev), NULL, skb, indev, NULL, 68 dev_net(indev), NULL, skb, indev, NULL,
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 43844144c9c4..e405eef0ae2e 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -361,7 +361,8 @@ out:
361} 361}
362 362
363static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, 363static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
364 __be32 group) 364 __be32 group,
365 u8 *igmp_type)
365{ 366{
366 struct sk_buff *skb; 367 struct sk_buff *skb;
367 struct igmphdr *ih; 368 struct igmphdr *ih;
@@ -411,6 +412,7 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
411 412
412 skb_set_transport_header(skb, skb->len); 413 skb_set_transport_header(skb, skb->len);
413 ih = igmp_hdr(skb); 414 ih = igmp_hdr(skb);
415 *igmp_type = IGMP_HOST_MEMBERSHIP_QUERY;
414 ih->type = IGMP_HOST_MEMBERSHIP_QUERY; 416 ih->type = IGMP_HOST_MEMBERSHIP_QUERY;
415 ih->code = (group ? br->multicast_last_member_interval : 417 ih->code = (group ? br->multicast_last_member_interval :
416 br->multicast_query_response_interval) / 418 br->multicast_query_response_interval) /
@@ -428,7 +430,8 @@ out:
428 430
429#if IS_ENABLED(CONFIG_IPV6) 431#if IS_ENABLED(CONFIG_IPV6)
430static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, 432static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
431 const struct in6_addr *group) 433 const struct in6_addr *grp,
434 u8 *igmp_type)
432{ 435{
433 struct sk_buff *skb; 436 struct sk_buff *skb;
434 struct ipv6hdr *ip6h; 437 struct ipv6hdr *ip6h;
@@ -487,16 +490,17 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
487 skb_set_transport_header(skb, skb->len); 490 skb_set_transport_header(skb, skb->len);
488 mldq = (struct mld_msg *) icmp6_hdr(skb); 491 mldq = (struct mld_msg *) icmp6_hdr(skb);
489 492
490 interval = ipv6_addr_any(group) ? 493 interval = ipv6_addr_any(grp) ?
491 br->multicast_query_response_interval : 494 br->multicast_query_response_interval :
492 br->multicast_last_member_interval; 495 br->multicast_last_member_interval;
493 496
497 *igmp_type = ICMPV6_MGM_QUERY;
494 mldq->mld_type = ICMPV6_MGM_QUERY; 498 mldq->mld_type = ICMPV6_MGM_QUERY;
495 mldq->mld_code = 0; 499 mldq->mld_code = 0;
496 mldq->mld_cksum = 0; 500 mldq->mld_cksum = 0;
497 mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval)); 501 mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval));
498 mldq->mld_reserved = 0; 502 mldq->mld_reserved = 0;
499 mldq->mld_mca = *group; 503 mldq->mld_mca = *grp;
500 504
501 /* checksum */ 505 /* checksum */
502 mldq->mld_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, 506 mldq->mld_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
@@ -513,14 +517,16 @@ out:
513#endif 517#endif
514 518
515static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br, 519static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
516 struct br_ip *addr) 520 struct br_ip *addr,
521 u8 *igmp_type)
517{ 522{
518 switch (addr->proto) { 523 switch (addr->proto) {
519 case htons(ETH_P_IP): 524 case htons(ETH_P_IP):
520 return br_ip4_multicast_alloc_query(br, addr->u.ip4); 525 return br_ip4_multicast_alloc_query(br, addr->u.ip4, igmp_type);
521#if IS_ENABLED(CONFIG_IPV6) 526#if IS_ENABLED(CONFIG_IPV6)
522 case htons(ETH_P_IPV6): 527 case htons(ETH_P_IPV6):
523 return br_ip6_multicast_alloc_query(br, &addr->u.ip6); 528 return br_ip6_multicast_alloc_query(br, &addr->u.ip6,
529 igmp_type);
524#endif 530#endif
525 } 531 }
526 return NULL; 532 return NULL;
@@ -829,18 +835,23 @@ static void __br_multicast_send_query(struct net_bridge *br,
829 struct br_ip *ip) 835 struct br_ip *ip)
830{ 836{
831 struct sk_buff *skb; 837 struct sk_buff *skb;
838 u8 igmp_type;
832 839
833 skb = br_multicast_alloc_query(br, ip); 840 skb = br_multicast_alloc_query(br, ip, &igmp_type);
834 if (!skb) 841 if (!skb)
835 return; 842 return;
836 843
837 if (port) { 844 if (port) {
838 skb->dev = port->dev; 845 skb->dev = port->dev;
846 br_multicast_count(br, port, skb->protocol, igmp_type,
847 BR_MCAST_DIR_TX);
839 NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, 848 NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
840 dev_net(port->dev), NULL, skb, NULL, skb->dev, 849 dev_net(port->dev), NULL, skb, NULL, skb->dev,
841 br_dev_queue_push_xmit); 850 br_dev_queue_push_xmit);
842 } else { 851 } else {
843 br_multicast_select_own_querier(br, ip, skb); 852 br_multicast_select_own_querier(br, ip, skb);
853 br_multicast_count(br, port, skb->protocol, igmp_type,
854 BR_MCAST_DIR_RX);
844 netif_rx(skb); 855 netif_rx(skb);
845 } 856 }
846} 857}
@@ -918,7 +929,7 @@ static void br_ip6_multicast_port_query_expired(unsigned long data)
918} 929}
919#endif 930#endif
920 931
921void br_multicast_add_port(struct net_bridge_port *port) 932int br_multicast_add_port(struct net_bridge_port *port)
922{ 933{
923 port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY; 934 port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
924 935
@@ -930,6 +941,11 @@ void br_multicast_add_port(struct net_bridge_port *port)
930 setup_timer(&port->ip6_own_query.timer, 941 setup_timer(&port->ip6_own_query.timer,
931 br_ip6_multicast_port_query_expired, (unsigned long)port); 942 br_ip6_multicast_port_query_expired, (unsigned long)port);
932#endif 943#endif
944 port->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats);
945 if (!port->mcast_stats)
946 return -ENOMEM;
947
948 return 0;
933} 949}
934 950
935void br_multicast_del_port(struct net_bridge_port *port) 951void br_multicast_del_port(struct net_bridge_port *port)
@@ -944,6 +960,7 @@ void br_multicast_del_port(struct net_bridge_port *port)
944 br_multicast_del_pg(br, pg); 960 br_multicast_del_pg(br, pg);
945 spin_unlock_bh(&br->multicast_lock); 961 spin_unlock_bh(&br->multicast_lock);
946 del_timer_sync(&port->multicast_router_timer); 962 del_timer_sync(&port->multicast_router_timer);
963 free_percpu(port->mcast_stats);
947} 964}
948 965
949static void br_multicast_enable(struct bridge_mcast_own_query *query) 966static void br_multicast_enable(struct bridge_mcast_own_query *query)
@@ -1583,6 +1600,39 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
1583} 1600}
1584#endif 1601#endif
1585 1602
1603static void br_multicast_err_count(const struct net_bridge *br,
1604 const struct net_bridge_port *p,
1605 __be16 proto)
1606{
1607 struct bridge_mcast_stats __percpu *stats;
1608 struct bridge_mcast_stats *pstats;
1609
1610 if (!br->multicast_stats_enabled)
1611 return;
1612
1613 if (p)
1614 stats = p->mcast_stats;
1615 else
1616 stats = br->mcast_stats;
1617 if (WARN_ON(!stats))
1618 return;
1619
1620 pstats = this_cpu_ptr(stats);
1621
1622 u64_stats_update_begin(&pstats->syncp);
1623 switch (proto) {
1624 case htons(ETH_P_IP):
1625 pstats->mstats.igmp_parse_errors++;
1626 break;
1627#if IS_ENABLED(CONFIG_IPV6)
1628 case htons(ETH_P_IPV6):
1629 pstats->mstats.mld_parse_errors++;
1630 break;
1631#endif
1632 }
1633 u64_stats_update_end(&pstats->syncp);
1634}
1635
1586static int br_multicast_ipv4_rcv(struct net_bridge *br, 1636static int br_multicast_ipv4_rcv(struct net_bridge *br,
1587 struct net_bridge_port *port, 1637 struct net_bridge_port *port,
1588 struct sk_buff *skb, 1638 struct sk_buff *skb,
@@ -1599,11 +1649,12 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
1599 BR_INPUT_SKB_CB(skb)->mrouters_only = 1; 1649 BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
1600 return 0; 1650 return 0;
1601 } else if (err < 0) { 1651 } else if (err < 0) {
1652 br_multicast_err_count(br, port, skb->protocol);
1602 return err; 1653 return err;
1603 } 1654 }
1604 1655
1605 BR_INPUT_SKB_CB(skb)->igmp = 1;
1606 ih = igmp_hdr(skb); 1656 ih = igmp_hdr(skb);
1657 BR_INPUT_SKB_CB(skb)->igmp = ih->type;
1607 1658
1608 switch (ih->type) { 1659 switch (ih->type) {
1609 case IGMP_HOST_MEMBERSHIP_REPORT: 1660 case IGMP_HOST_MEMBERSHIP_REPORT:
@@ -1625,6 +1676,9 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
1625 if (skb_trimmed && skb_trimmed != skb) 1676 if (skb_trimmed && skb_trimmed != skb)
1626 kfree_skb(skb_trimmed); 1677 kfree_skb(skb_trimmed);
1627 1678
1679 br_multicast_count(br, port, skb->protocol, BR_INPUT_SKB_CB(skb)->igmp,
1680 BR_MCAST_DIR_RX);
1681
1628 return err; 1682 return err;
1629} 1683}
1630 1684
@@ -1645,11 +1699,12 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
1645 BR_INPUT_SKB_CB(skb)->mrouters_only = 1; 1699 BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
1646 return 0; 1700 return 0;
1647 } else if (err < 0) { 1701 } else if (err < 0) {
1702 br_multicast_err_count(br, port, skb->protocol);
1648 return err; 1703 return err;
1649 } 1704 }
1650 1705
1651 BR_INPUT_SKB_CB(skb)->igmp = 1;
1652 mld = (struct mld_msg *)skb_transport_header(skb); 1706 mld = (struct mld_msg *)skb_transport_header(skb);
1707 BR_INPUT_SKB_CB(skb)->igmp = mld->mld_type;
1653 1708
1654 switch (mld->mld_type) { 1709 switch (mld->mld_type) {
1655 case ICMPV6_MGM_REPORT: 1710 case ICMPV6_MGM_REPORT:
@@ -1670,6 +1725,9 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
1670 if (skb_trimmed && skb_trimmed != skb) 1725 if (skb_trimmed && skb_trimmed != skb)
1671 kfree_skb(skb_trimmed); 1726 kfree_skb(skb_trimmed);
1672 1727
1728 br_multicast_count(br, port, skb->protocol, BR_INPUT_SKB_CB(skb)->igmp,
1729 BR_MCAST_DIR_RX);
1730
1673 return err; 1731 return err;
1674} 1732}
1675#endif 1733#endif
@@ -1677,6 +1735,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
1677int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, 1735int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
1678 struct sk_buff *skb, u16 vid) 1736 struct sk_buff *skb, u16 vid)
1679{ 1737{
1738 int ret = 0;
1739
1680 BR_INPUT_SKB_CB(skb)->igmp = 0; 1740 BR_INPUT_SKB_CB(skb)->igmp = 0;
1681 BR_INPUT_SKB_CB(skb)->mrouters_only = 0; 1741 BR_INPUT_SKB_CB(skb)->mrouters_only = 0;
1682 1742
@@ -1685,14 +1745,16 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
1685 1745
1686 switch (skb->protocol) { 1746 switch (skb->protocol) {
1687 case htons(ETH_P_IP): 1747 case htons(ETH_P_IP):
1688 return br_multicast_ipv4_rcv(br, port, skb, vid); 1748 ret = br_multicast_ipv4_rcv(br, port, skb, vid);
1749 break;
1689#if IS_ENABLED(CONFIG_IPV6) 1750#if IS_ENABLED(CONFIG_IPV6)
1690 case htons(ETH_P_IPV6): 1751 case htons(ETH_P_IPV6):
1691 return br_multicast_ipv6_rcv(br, port, skb, vid); 1752 ret = br_multicast_ipv6_rcv(br, port, skb, vid);
1753 break;
1692#endif 1754#endif
1693 } 1755 }
1694 1756
1695 return 0; 1757 return ret;
1696} 1758}
1697 1759
1698static void br_multicast_query_expired(struct net_bridge *br, 1760static void br_multicast_query_expired(struct net_bridge *br,
@@ -1831,6 +1893,8 @@ void br_multicast_dev_del(struct net_bridge *br)
1831 1893
1832out: 1894out:
1833 spin_unlock_bh(&br->multicast_lock); 1895 spin_unlock_bh(&br->multicast_lock);
1896
1897 free_percpu(br->mcast_stats);
1834} 1898}
1835 1899
1836int br_multicast_set_router(struct net_bridge *br, unsigned long val) 1900int br_multicast_set_router(struct net_bridge *br, unsigned long val)
@@ -2185,3 +2249,128 @@ unlock:
2185 return ret; 2249 return ret;
2186} 2250}
2187EXPORT_SYMBOL_GPL(br_multicast_has_querier_adjacent); 2251EXPORT_SYMBOL_GPL(br_multicast_has_querier_adjacent);
2252
2253static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats,
2254 __be16 proto, u8 type, u8 dir)
2255{
2256 struct bridge_mcast_stats *pstats = this_cpu_ptr(stats);
2257
2258 u64_stats_update_begin(&pstats->syncp);
2259 switch (proto) {
2260 case htons(ETH_P_IP):
2261 switch (type) {
2262 case IGMP_HOST_MEMBERSHIP_REPORT:
2263 pstats->mstats.igmp_v1reports[dir]++;
2264 break;
2265 case IGMPV2_HOST_MEMBERSHIP_REPORT:
2266 pstats->mstats.igmp_v2reports[dir]++;
2267 break;
2268 case IGMPV3_HOST_MEMBERSHIP_REPORT:
2269 pstats->mstats.igmp_v3reports[dir]++;
2270 break;
2271 case IGMP_HOST_MEMBERSHIP_QUERY:
2272 pstats->mstats.igmp_queries[dir]++;
2273 break;
2274 case IGMP_HOST_LEAVE_MESSAGE:
2275 pstats->mstats.igmp_leaves[dir]++;
2276 break;
2277 }
2278 break;
2279#if IS_ENABLED(CONFIG_IPV6)
2280 case htons(ETH_P_IPV6):
2281 switch (type) {
2282 case ICMPV6_MGM_REPORT:
2283 pstats->mstats.mld_v1reports[dir]++;
2284 break;
2285 case ICMPV6_MLD2_REPORT:
2286 pstats->mstats.mld_v2reports[dir]++;
2287 break;
2288 case ICMPV6_MGM_QUERY:
2289 pstats->mstats.mld_queries[dir]++;
2290 break;
2291 case ICMPV6_MGM_REDUCTION:
2292 pstats->mstats.mld_leaves[dir]++;
2293 break;
2294 }
2295 break;
2296#endif /* CONFIG_IPV6 */
2297 }
2298 u64_stats_update_end(&pstats->syncp);
2299}
2300
2301void br_multicast_count(struct net_bridge *br, const struct net_bridge_port *p,
2302 __be16 proto, u8 type, u8 dir)
2303{
2304 struct bridge_mcast_stats __percpu *stats;
2305
2306 /* if multicast_disabled is true then igmp type can't be set */
2307 if (!type || !br->multicast_stats_enabled)
2308 return;
2309
2310 if (p)
2311 stats = p->mcast_stats;
2312 else
2313 stats = br->mcast_stats;
2314 if (WARN_ON(!stats))
2315 return;
2316
2317 br_mcast_stats_add(stats, proto, type, dir);
2318}
2319
2320int br_multicast_init_stats(struct net_bridge *br)
2321{
2322 br->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats);
2323 if (!br->mcast_stats)
2324 return -ENOMEM;
2325
2326 return 0;
2327}
2328
2329static void mcast_stats_add_dir(u64 *dst, u64 *src)
2330{
2331 dst[BR_MCAST_DIR_RX] += src[BR_MCAST_DIR_RX];
2332 dst[BR_MCAST_DIR_TX] += src[BR_MCAST_DIR_TX];
2333}
2334
2335void br_multicast_get_stats(const struct net_bridge *br,
2336 const struct net_bridge_port *p,
2337 struct br_mcast_stats *dest)
2338{
2339 struct bridge_mcast_stats __percpu *stats;
2340 struct br_mcast_stats tdst;
2341 int i;
2342
2343 memset(dest, 0, sizeof(*dest));
2344 if (p)
2345 stats = p->mcast_stats;
2346 else
2347 stats = br->mcast_stats;
2348 if (WARN_ON(!stats))
2349 return;
2350
2351 memset(&tdst, 0, sizeof(tdst));
2352 for_each_possible_cpu(i) {
2353 struct bridge_mcast_stats *cpu_stats = per_cpu_ptr(stats, i);
2354 struct br_mcast_stats temp;
2355 unsigned int start;
2356
2357 do {
2358 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
2359 memcpy(&temp, &cpu_stats->mstats, sizeof(temp));
2360 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
2361
2362 mcast_stats_add_dir(tdst.igmp_queries, temp.igmp_queries);
2363 mcast_stats_add_dir(tdst.igmp_leaves, temp.igmp_leaves);
2364 mcast_stats_add_dir(tdst.igmp_v1reports, temp.igmp_v1reports);
2365 mcast_stats_add_dir(tdst.igmp_v2reports, temp.igmp_v2reports);
2366 mcast_stats_add_dir(tdst.igmp_v3reports, temp.igmp_v3reports);
2367 tdst.igmp_parse_errors += temp.igmp_parse_errors;
2368
2369 mcast_stats_add_dir(tdst.mld_queries, temp.mld_queries);
2370 mcast_stats_add_dir(tdst.mld_leaves, temp.mld_leaves);
2371 mcast_stats_add_dir(tdst.mld_v1reports, temp.mld_v1reports);
2372 mcast_stats_add_dir(tdst.mld_v2reports, temp.mld_v2reports);
2373 tdst.mld_parse_errors += temp.mld_parse_errors;
2374 }
2375 memcpy(dest, &tdst, sizeof(*dest));
2376}
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index ed75ff9ff9e6..f2a29e467e78 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -851,6 +851,7 @@ static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = {
851 [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NLA_U8 }, 851 [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NLA_U8 },
852 [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NLA_U16 }, 852 [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NLA_U16 },
853 [IFLA_BR_VLAN_STATS_ENABLED] = { .type = NLA_U8 }, 853 [IFLA_BR_VLAN_STATS_ENABLED] = { .type = NLA_U8 },
854 [IFLA_BR_MCAST_STATS_ENABLED] = { .type = NLA_U8 },
854}; 855};
855 856
856static int br_changelink(struct net_device *brdev, struct nlattr *tb[], 857static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
@@ -1055,6 +1056,13 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
1055 1056
1056 br->multicast_startup_query_interval = clock_t_to_jiffies(val); 1057 br->multicast_startup_query_interval = clock_t_to_jiffies(val);
1057 } 1058 }
1059
1060 if (data[IFLA_BR_MCAST_STATS_ENABLED]) {
1061 __u8 mcast_stats;
1062
1063 mcast_stats = nla_get_u8(data[IFLA_BR_MCAST_STATS_ENABLED]);
1064 br->multicast_stats_enabled = !!mcast_stats;
1065 }
1058#endif 1066#endif
1059#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 1067#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
1060 if (data[IFLA_BR_NF_CALL_IPTABLES]) { 1068 if (data[IFLA_BR_NF_CALL_IPTABLES]) {
@@ -1110,6 +1118,7 @@ static size_t br_get_size(const struct net_device *brdev)
1110 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_SNOOPING */ 1118 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_SNOOPING */
1111 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_QUERY_USE_IFADDR */ 1119 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_QUERY_USE_IFADDR */
1112 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_QUERIER */ 1120 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_QUERIER */
1121 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_STATS_ENABLED */
1113 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_HASH_ELASTICITY */ 1122 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_HASH_ELASTICITY */
1114 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_HASH_MAX */ 1123 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_HASH_MAX */
1115 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_LAST_MEMBER_CNT */ 1124 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_LAST_MEMBER_CNT */
@@ -1187,6 +1196,8 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
1187 nla_put_u8(skb, IFLA_BR_MCAST_QUERY_USE_IFADDR, 1196 nla_put_u8(skb, IFLA_BR_MCAST_QUERY_USE_IFADDR,
1188 br->multicast_query_use_ifaddr) || 1197 br->multicast_query_use_ifaddr) ||
1189 nla_put_u8(skb, IFLA_BR_MCAST_QUERIER, br->multicast_querier) || 1198 nla_put_u8(skb, IFLA_BR_MCAST_QUERIER, br->multicast_querier) ||
1199 nla_put_u8(skb, IFLA_BR_MCAST_STATS_ENABLED,
1200 br->multicast_stats_enabled) ||
1190 nla_put_u32(skb, IFLA_BR_MCAST_HASH_ELASTICITY, 1201 nla_put_u32(skb, IFLA_BR_MCAST_HASH_ELASTICITY,
1191 br->hash_elasticity) || 1202 br->hash_elasticity) ||
1192 nla_put_u32(skb, IFLA_BR_MCAST_HASH_MAX, br->hash_max) || 1203 nla_put_u32(skb, IFLA_BR_MCAST_HASH_MAX, br->hash_max) ||
@@ -1242,21 +1253,21 @@ static size_t bridge_get_linkxstats_size(const struct net_device *dev)
1242 int numvls = 0; 1253 int numvls = 0;
1243 1254
1244 vg = br_vlan_group(br); 1255 vg = br_vlan_group(br);
1245 if (!vg) 1256 if (vg) {
1246 return 0; 1257 /* we need to count all, even placeholder entries */
1247 1258 list_for_each_entry(v, &vg->vlan_list, vlist)
1248 /* we need to count all, even placeholder entries */ 1259 numvls++;
1249 list_for_each_entry(v, &vg->vlan_list, vlist) 1260 }
1250 numvls++;
1251 1261
1252 /* account for the vlans and the link xstats type nest attribute */
1253 return numvls * nla_total_size(sizeof(struct bridge_vlan_xstats)) + 1262 return numvls * nla_total_size(sizeof(struct bridge_vlan_xstats)) +
1263 nla_total_size(sizeof(struct br_mcast_stats)) +
1254 nla_total_size(0); 1264 nla_total_size(0);
1255} 1265}
1256 1266
1257static size_t brport_get_linkxstats_size(const struct net_device *dev) 1267static size_t brport_get_linkxstats_size(const struct net_device *dev)
1258{ 1268{
1259 return nla_total_size(0); 1269 return nla_total_size(sizeof(struct br_mcast_stats)) +
1270 nla_total_size(0);
1260} 1271}
1261 1272
1262static size_t br_get_linkxstats_size(const struct net_device *dev, int attr) 1273static size_t br_get_linkxstats_size(const struct net_device *dev, int attr)
@@ -1280,37 +1291,50 @@ static int bridge_fill_linkxstats(struct sk_buff *skb,
1280 int *prividx) 1291 int *prividx)
1281{ 1292{
1282 struct net_bridge *br = netdev_priv(dev); 1293 struct net_bridge *br = netdev_priv(dev);
1294 struct nlattr *nla __maybe_unused;
1283 struct net_bridge_vlan_group *vg; 1295 struct net_bridge_vlan_group *vg;
1284 struct net_bridge_vlan *v; 1296 struct net_bridge_vlan *v;
1285 struct nlattr *nest; 1297 struct nlattr *nest;
1286 int vl_idx = 0; 1298 int vl_idx = 0;
1287 1299
1288 vg = br_vlan_group(br);
1289 if (!vg)
1290 goto out;
1291 nest = nla_nest_start(skb, LINK_XSTATS_TYPE_BRIDGE); 1300 nest = nla_nest_start(skb, LINK_XSTATS_TYPE_BRIDGE);
1292 if (!nest) 1301 if (!nest)
1293 return -EMSGSIZE; 1302 return -EMSGSIZE;
1294 list_for_each_entry(v, &vg->vlan_list, vlist) {
1295 struct bridge_vlan_xstats vxi;
1296 struct br_vlan_stats stats;
1297 1303
1298 if (++vl_idx < *prividx) 1304 vg = br_vlan_group(br);
1299 continue; 1305 if (vg) {
1300 memset(&vxi, 0, sizeof(vxi)); 1306 list_for_each_entry(v, &vg->vlan_list, vlist) {
1301 vxi.vid = v->vid; 1307 struct bridge_vlan_xstats vxi;
1302 br_vlan_get_stats(v, &stats); 1308 struct br_vlan_stats stats;
1303 vxi.rx_bytes = stats.rx_bytes; 1309
1304 vxi.rx_packets = stats.rx_packets; 1310 if (++vl_idx < *prividx)
1305 vxi.tx_bytes = stats.tx_bytes; 1311 continue;
1306 vxi.tx_packets = stats.tx_packets; 1312 memset(&vxi, 0, sizeof(vxi));
1307 1313 vxi.vid = v->vid;
1308 if (nla_put(skb, BRIDGE_XSTATS_VLAN, sizeof(vxi), &vxi)) 1314 br_vlan_get_stats(v, &stats);
1315 vxi.rx_bytes = stats.rx_bytes;
1316 vxi.rx_packets = stats.rx_packets;
1317 vxi.tx_bytes = stats.tx_bytes;
1318 vxi.tx_packets = stats.tx_packets;
1319
1320 if (nla_put(skb, BRIDGE_XSTATS_VLAN, sizeof(vxi), &vxi))
1321 goto nla_put_failure;
1322 }
1323 }
1324
1325#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
1326 if (++vl_idx >= *prividx) {
1327 nla = nla_reserve_64bit(skb, BRIDGE_XSTATS_MCAST,
1328 sizeof(struct br_mcast_stats),
1329 BRIDGE_XSTATS_PAD);
1330 if (!nla)
1309 goto nla_put_failure; 1331 goto nla_put_failure;
1332 br_multicast_get_stats(br, NULL, nla_data(nla));
1310 } 1333 }
1334#endif
1311 nla_nest_end(skb, nest); 1335 nla_nest_end(skb, nest);
1312 *prividx = 0; 1336 *prividx = 0;
1313out: 1337
1314 return 0; 1338 return 0;
1315 1339
1316nla_put_failure: 1340nla_put_failure:
@@ -1324,11 +1348,26 @@ static int brport_fill_linkxstats(struct sk_buff *skb,
1324 const struct net_device *dev, 1348 const struct net_device *dev,
1325 int *prividx) 1349 int *prividx)
1326{ 1350{
1351 struct net_bridge_port *p = br_port_get_rtnl(dev);
1352 struct nlattr *nla __maybe_unused;
1327 struct nlattr *nest; 1353 struct nlattr *nest;
1328 1354
1355 if (!p)
1356 return 0;
1357
1329 nest = nla_nest_start(skb, LINK_XSTATS_TYPE_BRIDGE); 1358 nest = nla_nest_start(skb, LINK_XSTATS_TYPE_BRIDGE);
1330 if (!nest) 1359 if (!nest)
1331 return -EMSGSIZE; 1360 return -EMSGSIZE;
1361#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
1362 nla = nla_reserve_64bit(skb, BRIDGE_XSTATS_MCAST,
1363 sizeof(struct br_mcast_stats),
1364 BRIDGE_XSTATS_PAD);
1365 if (!nla) {
1366 nla_nest_end(skb, nest);
1367 return -EMSGSIZE;
1368 }
1369 br_multicast_get_stats(p->br, p, nla_data(nla));
1370#endif
1332 nla_nest_end(skb, nest); 1371 nla_nest_end(skb, nest);
1333 1372
1334 return 0; 1373 return 0;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 52edecf3c294..4dc851166ad1 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -75,6 +75,12 @@ struct bridge_mcast_querier {
75 struct br_ip addr; 75 struct br_ip addr;
76 struct net_bridge_port __rcu *port; 76 struct net_bridge_port __rcu *port;
77}; 77};
78
79/* IGMP/MLD statistics */
80struct bridge_mcast_stats {
81 struct br_mcast_stats mstats;
82 struct u64_stats_sync syncp;
83};
78#endif 84#endif
79 85
80struct br_vlan_stats { 86struct br_vlan_stats {
@@ -229,6 +235,7 @@ struct net_bridge_port
229 struct bridge_mcast_own_query ip6_own_query; 235 struct bridge_mcast_own_query ip6_own_query;
230#endif /* IS_ENABLED(CONFIG_IPV6) */ 236#endif /* IS_ENABLED(CONFIG_IPV6) */
231 unsigned char multicast_router; 237 unsigned char multicast_router;
238 struct bridge_mcast_stats __percpu *mcast_stats;
232 struct timer_list multicast_router_timer; 239 struct timer_list multicast_router_timer;
233 struct hlist_head mglist; 240 struct hlist_head mglist;
234 struct hlist_node rlist; 241 struct hlist_node rlist;
@@ -315,6 +322,7 @@ struct net_bridge
315 u8 multicast_querier:1; 322 u8 multicast_querier:1;
316 u8 multicast_query_use_ifaddr:1; 323 u8 multicast_query_use_ifaddr:1;
317 u8 has_ipv6_addr:1; 324 u8 has_ipv6_addr:1;
325 u8 multicast_stats_enabled:1;
318 326
319 u32 hash_elasticity; 327 u32 hash_elasticity;
320 u32 hash_max; 328 u32 hash_max;
@@ -337,6 +345,7 @@ struct net_bridge
337 struct bridge_mcast_other_query ip4_other_query; 345 struct bridge_mcast_other_query ip4_other_query;
338 struct bridge_mcast_own_query ip4_own_query; 346 struct bridge_mcast_own_query ip4_own_query;
339 struct bridge_mcast_querier ip4_querier; 347 struct bridge_mcast_querier ip4_querier;
348 struct bridge_mcast_stats __percpu *mcast_stats;
340#if IS_ENABLED(CONFIG_IPV6) 349#if IS_ENABLED(CONFIG_IPV6)
341 struct bridge_mcast_other_query ip6_other_query; 350 struct bridge_mcast_other_query ip6_other_query;
342 struct bridge_mcast_own_query ip6_own_query; 351 struct bridge_mcast_own_query ip6_own_query;
@@ -543,7 +552,7 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
543 struct sk_buff *skb, u16 vid); 552 struct sk_buff *skb, u16 vid);
544struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, 553struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
545 struct sk_buff *skb, u16 vid); 554 struct sk_buff *skb, u16 vid);
546void br_multicast_add_port(struct net_bridge_port *port); 555int br_multicast_add_port(struct net_bridge_port *port);
547void br_multicast_del_port(struct net_bridge_port *port); 556void br_multicast_del_port(struct net_bridge_port *port);
548void br_multicast_enable_port(struct net_bridge_port *port); 557void br_multicast_enable_port(struct net_bridge_port *port);
549void br_multicast_disable_port(struct net_bridge_port *port); 558void br_multicast_disable_port(struct net_bridge_port *port);
@@ -576,6 +585,12 @@ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
576 struct br_ip *group, int type, u8 flags); 585 struct br_ip *group, int type, u8 flags);
577void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port, 586void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port,
578 int type); 587 int type);
588void br_multicast_count(struct net_bridge *br, const struct net_bridge_port *p,
589 __be16 proto, u8 type, u8 dir);
590int br_multicast_init_stats(struct net_bridge *br);
591void br_multicast_get_stats(const struct net_bridge *br,
592 const struct net_bridge_port *p,
593 struct br_mcast_stats *dest);
579 594
580#define mlock_dereference(X, br) \ 595#define mlock_dereference(X, br) \
581 rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock)) 596 rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
@@ -623,6 +638,11 @@ static inline bool br_multicast_querier_exists(struct net_bridge *br,
623 return false; 638 return false;
624 } 639 }
625} 640}
641
642static inline int br_multicast_igmp_type(const struct sk_buff *skb)
643{
644 return BR_INPUT_SKB_CB(skb)->igmp;
645}
626#else 646#else
627static inline int br_multicast_rcv(struct net_bridge *br, 647static inline int br_multicast_rcv(struct net_bridge *br,
628 struct net_bridge_port *port, 648 struct net_bridge_port *port,
@@ -638,8 +658,9 @@ static inline struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
638 return NULL; 658 return NULL;
639} 659}
640 660
641static inline void br_multicast_add_port(struct net_bridge_port *port) 661static inline int br_multicast_add_port(struct net_bridge_port *port)
642{ 662{
663 return 0;
643} 664}
644 665
645static inline void br_multicast_del_port(struct net_bridge_port *port) 666static inline void br_multicast_del_port(struct net_bridge_port *port)
@@ -695,6 +716,22 @@ static inline void br_mdb_init(void)
695static inline void br_mdb_uninit(void) 716static inline void br_mdb_uninit(void)
696{ 717{
697} 718}
719
720static inline void br_multicast_count(struct net_bridge *br,
721 const struct net_bridge_port *p,
722 __be16 proto, u8 type, u8 dir)
723{
724}
725
726static inline int br_multicast_init_stats(struct net_bridge *br)
727{
728 return 0;
729}
730
731static inline int br_multicast_igmp_type(const struct sk_buff *skb)
732{
733 return 0;
734}
698#endif 735#endif
699 736
700/* br_vlan.c */ 737/* br_vlan.c */
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index beb47071e38d..e120307c6e36 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -618,6 +618,30 @@ static ssize_t multicast_startup_query_interval_store(
618 return store_bridge_parm(d, buf, len, set_startup_query_interval); 618 return store_bridge_parm(d, buf, len, set_startup_query_interval);
619} 619}
620static DEVICE_ATTR_RW(multicast_startup_query_interval); 620static DEVICE_ATTR_RW(multicast_startup_query_interval);
621
622static ssize_t multicast_stats_enabled_show(struct device *d,
623 struct device_attribute *attr,
624 char *buf)
625{
626 struct net_bridge *br = to_bridge(d);
627
628 return sprintf(buf, "%u\n", br->multicast_stats_enabled);
629}
630
631static int set_stats_enabled(struct net_bridge *br, unsigned long val)
632{
633 br->multicast_stats_enabled = !!val;
634 return 0;
635}
636
637static ssize_t multicast_stats_enabled_store(struct device *d,
638 struct device_attribute *attr,
639 const char *buf,
640 size_t len)
641{
642 return store_bridge_parm(d, buf, len, set_stats_enabled);
643}
644static DEVICE_ATTR_RW(multicast_stats_enabled);
621#endif 645#endif
622#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 646#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
623static ssize_t nf_call_iptables_show( 647static ssize_t nf_call_iptables_show(
@@ -784,6 +808,7 @@ static struct attribute *bridge_attrs[] = {
784 &dev_attr_multicast_query_interval.attr, 808 &dev_attr_multicast_query_interval.attr,
785 &dev_attr_multicast_query_response_interval.attr, 809 &dev_attr_multicast_query_response_interval.attr,
786 &dev_attr_multicast_startup_query_interval.attr, 810 &dev_attr_multicast_startup_query_interval.attr,
811 &dev_attr_multicast_stats_enabled.attr,
787#endif 812#endif
788#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 813#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
789 &dev_attr_nf_call_iptables.attr, 814 &dev_attr_nf_call_iptables.attr,