net: bridge: mcast: dump ipv4 querier state
Add support for dumping global IPv4 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_IP_ADDRESS] - ip address of the querier `[BRIDGE_QUERIER_IP_PORT] - bridge port ifindex where the querier was seen (set only if external querier) `[BRIDGE_QUERIER_IP_OTHER_TIMER] - other querier timeout Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
c3fb3698f9
Коммит
c7fa1d9b1f
|
@ -770,4 +770,14 @@ struct br_boolopt_multi {
|
|||
__u32 optval;
|
||||
__u32 optmask;
|
||||
};
|
||||
|
||||
enum {
|
||||
BRIDGE_QUERIER_UNSPEC,
|
||||
BRIDGE_QUERIER_IP_ADDRESS,
|
||||
BRIDGE_QUERIER_IP_PORT,
|
||||
BRIDGE_QUERIER_IP_OTHER_TIMER,
|
||||
BRIDGE_QUERIER_PAD,
|
||||
__BRIDGE_QUERIER_MAX
|
||||
};
|
||||
#define BRIDGE_QUERIER_MAX (__BRIDGE_QUERIER_MAX - 1)
|
||||
#endif /* _UAPI_LINUX_IF_BRIDGE_H */
|
||||
|
|
|
@ -479,6 +479,7 @@ enum {
|
|||
IFLA_BR_MCAST_MLD_VERSION,
|
||||
IFLA_BR_VLAN_STATS_PER_PORT,
|
||||
IFLA_BR_MULTI_BOOLOPT,
|
||||
IFLA_BR_MCAST_QUERIER_STATE,
|
||||
__IFLA_BR_MAX,
|
||||
};
|
||||
|
||||
|
|
|
@ -2905,6 +2905,79 @@ update:
|
|||
return true;
|
||||
}
|
||||
|
||||
static struct net_bridge_port *
|
||||
__br_multicast_get_querier_port(struct net_bridge *br,
|
||||
const struct bridge_mcast_querier *querier)
|
||||
{
|
||||
int port_ifidx = READ_ONCE(querier->port_ifidx);
|
||||
struct net_bridge_port *p;
|
||||
struct net_device *dev;
|
||||
|
||||
if (port_ifidx == 0)
|
||||
return NULL;
|
||||
|
||||
dev = dev_get_by_index_rcu(dev_net(br->dev), port_ifidx);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
p = br_port_get_rtnl_rcu(dev);
|
||||
if (!p || p->br != br)
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t br_multicast_querier_state_size(void)
|
||||
{
|
||||
return nla_total_size(sizeof(0)) + /* nest attribute */
|
||||
nla_total_size(sizeof(__be32)) + /* BRIDGE_QUERIER_IP_ADDRESS */
|
||||
nla_total_size(sizeof(int)) + /* BRIDGE_QUERIER_IP_PORT */
|
||||
nla_total_size_64bit(sizeof(u64)); /* BRIDGE_QUERIER_IP_OTHER_TIMER */
|
||||
}
|
||||
|
||||
/* protected by rtnl or rcu */
|
||||
int br_multicast_dump_querier_state(struct sk_buff *skb,
|
||||
const struct net_bridge_mcast *brmctx,
|
||||
int nest_attr)
|
||||
{
|
||||
struct bridge_mcast_querier querier = {};
|
||||
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();
|
||||
br_multicast_read_querier(&brmctx->ip4_querier, &querier);
|
||||
if (nla_put_in_addr(skb, BRIDGE_QUERIER_IP_ADDRESS,
|
||||
querier.addr.src.ip4)) {
|
||||
rcu_read_unlock();
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
p = __br_multicast_get_querier_port(brmctx->br, &querier);
|
||||
if (timer_pending(&brmctx->ip4_other_query.timer) &&
|
||||
(nla_put_u64_64bit(skb, BRIDGE_QUERIER_IP_OTHER_TIMER,
|
||||
br_timer_value(&brmctx->ip4_other_query.timer),
|
||||
BRIDGE_QUERIER_PAD) ||
|
||||
(p && nla_put_u32(skb, BRIDGE_QUERIER_IP_PORT, p->dev->ifindex)))) {
|
||||
rcu_read_unlock();
|
||||
goto out_err;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
nla_nest_end(skb, nest);
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
nla_nest_cancel(skb, nest);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
br_multicast_update_query_timer(struct net_bridge_mcast *brmctx,
|
||||
struct bridge_mcast_other_query *query,
|
||||
|
|
|
@ -1501,6 +1501,7 @@ static size_t br_get_size(const struct net_device *brdev)
|
|||
nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_MCAST_STARTUP_QUERY_INTVL */
|
||||
nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_IGMP_VERSION */
|
||||
nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_MLD_VERSION */
|
||||
br_multicast_querier_state_size() + /* IFLA_BR_MCAST_QUERIER_STATE */
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
nla_total_size(sizeof(u8)) + /* IFLA_BR_NF_CALL_IPTABLES */
|
||||
|
@ -1587,7 +1588,9 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
|
|||
nla_put_u32(skb, IFLA_BR_MCAST_STARTUP_QUERY_CNT,
|
||||
br->multicast_ctx.multicast_startup_query_count) ||
|
||||
nla_put_u8(skb, IFLA_BR_MCAST_IGMP_VERSION,
|
||||
br->multicast_ctx.multicast_igmp_version))
|
||||
br->multicast_ctx.multicast_igmp_version) ||
|
||||
br_multicast_dump_querier_state(skb, &br->multicast_ctx,
|
||||
IFLA_BR_MCAST_QUERIER_STATE))
|
||||
return -EMSGSIZE;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (nla_put_u8(skb, IFLA_BR_MCAST_MLD_VERSION,
|
||||
|
|
|
@ -948,6 +948,10 @@ int br_mdb_replay(struct net_device *br_dev, struct net_device *dev,
|
|||
struct netlink_ext_ack *extack);
|
||||
int br_rports_fill_info(struct sk_buff *skb,
|
||||
const struct net_bridge_mcast *brmctx);
|
||||
int br_multicast_dump_querier_state(struct sk_buff *skb,
|
||||
const struct net_bridge_mcast *brmctx,
|
||||
int nest_attr);
|
||||
size_t br_multicast_querier_state_size(void);
|
||||
|
||||
static inline bool br_group_is_l2(const struct br_ip *group)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче