net: bridge: mcast: dump ipv6 querier state
authorNikolay Aleksandrov <nikolay@nvidia.com>
Fri, 13 Aug 2021 15:00:01 +0000 (18:00 +0300)
committerDavid S. Miller <davem@davemloft.net>
Sat, 14 Aug 2021 13:02:43 +0000 (14:02 +0100)
Add support for dumping global IPv6 querier state, we dump the state
only if our own querier is enabled or there has been another external
querier which has won the election. For the bridge global state we use
a new attribute IFLA_BR_MCAST_QUERIER_STATE and embed the state inside.
The structure is:
  [IFLA_BR_MCAST_QUERIER_STATE]
   `[BRIDGE_QUERIER_IPV6_ADDRESS] - ip address of the querier
   `[BRIDGE_QUERIER_IPV6_PORT]    - bridge port ifindex where the querier
                                    was seen (set only if external querier)
   `[BRIDGE_QUERIER_IPV6_OTHER_TIMER]   -  other querier timeout

IPv4 and IPv6 attributes are embedded at the same level of
IFLA_BR_MCAST_QUERIER_STATE. If we didn't dump anything we cancel the nest
and return.

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/if_bridge.h
net/bridge/br_multicast.c

index e0fff67fcd888492b327290fc7ac89e0108ed456..eceaad200bf6033b8249f9798e487bab4b2de84d 100644 (file)
@@ -777,6 +777,9 @@ enum {
        BRIDGE_QUERIER_IP_PORT,
        BRIDGE_QUERIER_IP_OTHER_TIMER,
        BRIDGE_QUERIER_PAD,
+       BRIDGE_QUERIER_IPV6_ADDRESS,
+       BRIDGE_QUERIER_IPV6_PORT,
+       BRIDGE_QUERIER_IPV6_OTHER_TIMER,
        __BRIDGE_QUERIER_MAX
 };
 #define BRIDGE_QUERIER_MAX (__BRIDGE_QUERIER_MAX - 1)
index 4513bc13b6d3452661c6c10586b05017a92fd32c..0e5d6ba034574ef96ef0479d39881c870aa4159e 100644 (file)
@@ -2943,15 +2943,15 @@ int br_multicast_dump_querier_state(struct sk_buff *skb,
        struct net_bridge_port *p;
        struct nlattr *nest;
 
-       if (!brmctx->multicast_querier &&
-           !timer_pending(&brmctx->ip4_other_query.timer))
-               return 0;
-
        nest = nla_nest_start(skb, nest_attr);
        if (!nest)
                return -EMSGSIZE;
 
        rcu_read_lock();
+       if (!brmctx->multicast_querier &&
+           !timer_pending(&brmctx->ip4_other_query.timer))
+               goto out_v6;
+
        br_multicast_read_querier(&brmctx->ip4_querier, &querier);
        if (nla_put_in_addr(skb, BRIDGE_QUERIER_IP_ADDRESS,
                            querier.addr.src.ip4)) {
@@ -2968,8 +2968,36 @@ int br_multicast_dump_querier_state(struct sk_buff *skb,
                rcu_read_unlock();
                goto out_err;
        }
+
+out_v6:
+#if IS_ENABLED(CONFIG_IPV6)
+       if (!brmctx->multicast_querier &&
+           !timer_pending(&brmctx->ip6_other_query.timer))
+               goto out;
+
+       br_multicast_read_querier(&brmctx->ip6_querier, &querier);
+       if (nla_put_in6_addr(skb, BRIDGE_QUERIER_IPV6_ADDRESS,
+                            &querier.addr.src.ip6)) {
+               rcu_read_unlock();
+               goto out_err;
+       }
+
+       p = __br_multicast_get_querier_port(brmctx->br, &querier);
+       if (timer_pending(&brmctx->ip6_other_query.timer) &&
+           (nla_put_u64_64bit(skb, BRIDGE_QUERIER_IPV6_OTHER_TIMER,
+                              br_timer_value(&brmctx->ip6_other_query.timer),
+                              BRIDGE_QUERIER_PAD) ||
+            (p && nla_put_u32(skb, BRIDGE_QUERIER_IPV6_PORT,
+                              p->dev->ifindex)))) {
+               rcu_read_unlock();
+               goto out_err;
+       }
+out:
+#endif
        rcu_read_unlock();
        nla_nest_end(skb, nest);
+       if (!nla_len(nest))
+               nla_nest_cancel(skb, nest);
 
        return 0;