Commit d67b8c61 authored by Nicolas Dichtel's avatar Nicolas Dichtel Committed by David S. Miller

netconf: advertise mc_forwarding status

This patch advertise the MC_FORWARDING status for IPv4 and IPv6.
This field is readonly, only multicast engine in the kernel updates it.
Signed-off-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e8ad1a8f
...@@ -171,6 +171,9 @@ struct in_ifaddr { ...@@ -171,6 +171,9 @@ struct in_ifaddr {
extern int register_inetaddr_notifier(struct notifier_block *nb); extern int register_inetaddr_notifier(struct notifier_block *nb);
extern int unregister_inetaddr_notifier(struct notifier_block *nb); extern int unregister_inetaddr_notifier(struct notifier_block *nb);
extern void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
struct ipv4_devconf *devconf);
extern struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref); extern struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref);
static inline struct net_device *ip_dev_find(struct net *net, __be32 addr) static inline struct net_device *ip_dev_find(struct net *net, __be32 addr)
{ {
......
...@@ -172,6 +172,9 @@ extern bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, ...@@ -172,6 +172,9 @@ extern bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
extern int register_inet6addr_notifier(struct notifier_block *nb); extern int register_inet6addr_notifier(struct notifier_block *nb);
extern int unregister_inet6addr_notifier(struct notifier_block *nb); extern int unregister_inet6addr_notifier(struct notifier_block *nb);
extern void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
struct ipv6_devconf *devconf);
/** /**
* __in6_dev_get - get inet6_dev pointer from netdevice * __in6_dev_get - get inet6_dev pointer from netdevice
* @dev: network device * @dev: network device
......
...@@ -13,6 +13,7 @@ enum { ...@@ -13,6 +13,7 @@ enum {
NETCONFA_IFINDEX, NETCONFA_IFINDEX,
NETCONFA_FORWARDING, NETCONFA_FORWARDING,
NETCONFA_RP_FILTER, NETCONFA_RP_FILTER,
NETCONFA_MC_FORWARDING,
__NETCONFA_MAX __NETCONFA_MAX
}; };
#define NETCONFA_MAX (__NETCONFA_MAX - 1) #define NETCONFA_MAX (__NETCONFA_MAX - 1)
......
...@@ -1453,6 +1453,8 @@ static int inet_netconf_msgsize_devconf(int type) ...@@ -1453,6 +1453,8 @@ static int inet_netconf_msgsize_devconf(int type)
size += nla_total_size(4); size += nla_total_size(4);
if (type == -1 || type == NETCONFA_RP_FILTER) if (type == -1 || type == NETCONFA_RP_FILTER)
size += nla_total_size(4); size += nla_total_size(4);
if (type == -1 || type == NETCONFA_MC_FORWARDING)
size += nla_total_size(4);
return size; return size;
} }
...@@ -1485,6 +1487,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, ...@@ -1485,6 +1487,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
nla_put_s32(skb, NETCONFA_RP_FILTER, nla_put_s32(skb, NETCONFA_RP_FILTER,
IPV4_DEVCONF(*devconf, RP_FILTER)) < 0) IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
goto nla_put_failure; goto nla_put_failure;
if ((type == -1 || type == NETCONFA_MC_FORWARDING) &&
nla_put_s32(skb, NETCONFA_MC_FORWARDING,
IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
goto nla_put_failure;
return nlmsg_end(skb, nlh); return nlmsg_end(skb, nlh);
...@@ -1493,7 +1499,7 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, ...@@ -1493,7 +1499,7 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
return -EMSGSIZE; return -EMSGSIZE;
} }
static void inet_netconf_notify_devconf(struct net *net, int type, int ifindex, void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
struct ipv4_devconf *devconf) struct ipv4_devconf *devconf)
{ {
struct sk_buff *skb; struct sk_buff *skb;
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#include <net/checksum.h> #include <net/checksum.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/fib_rules.h> #include <net/fib_rules.h>
#include <linux/netconf.h>
#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2) #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
#define CONFIG_IP_PIMSM 1 #define CONFIG_IP_PIMSM 1
...@@ -582,6 +583,9 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify, ...@@ -582,6 +583,9 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify,
in_dev = __in_dev_get_rtnl(dev); in_dev = __in_dev_get_rtnl(dev);
if (in_dev) { if (in_dev) {
IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--; IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
inet_netconf_notify_devconf(dev_net(dev),
NETCONFA_MC_FORWARDING,
dev->ifindex, &in_dev->cnf);
ip_rt_multicast_event(in_dev); ip_rt_multicast_event(in_dev);
} }
...@@ -772,6 +776,8 @@ static int vif_add(struct net *net, struct mr_table *mrt, ...@@ -772,6 +776,8 @@ static int vif_add(struct net *net, struct mr_table *mrt,
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
} }
IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
inet_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING, dev->ifindex,
&in_dev->cnf);
ip_rt_multicast_event(in_dev); ip_rt_multicast_event(in_dev);
/* Fill in the VIF structures */ /* Fill in the VIF structures */
...@@ -1185,6 +1191,9 @@ static void mrtsock_destruct(struct sock *sk) ...@@ -1185,6 +1191,9 @@ static void mrtsock_destruct(struct sock *sk)
ipmr_for_each_table(mrt, net) { ipmr_for_each_table(mrt, net) {
if (sk == rtnl_dereference(mrt->mroute_sk)) { if (sk == rtnl_dereference(mrt->mroute_sk)) {
IPV4_DEVCONF_ALL(net, MC_FORWARDING)--; IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
inet_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING,
NETCONFA_IFINDEX_ALL,
net->ipv4.devconf_all);
RCU_INIT_POINTER(mrt->mroute_sk, NULL); RCU_INIT_POINTER(mrt->mroute_sk, NULL);
mroute_clean_tables(mrt); mroute_clean_tables(mrt);
} }
...@@ -1236,6 +1245,9 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi ...@@ -1236,6 +1245,9 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
if (ret == 0) { if (ret == 0) {
rcu_assign_pointer(mrt->mroute_sk, sk); rcu_assign_pointer(mrt->mroute_sk, sk);
IPV4_DEVCONF_ALL(net, MC_FORWARDING)++; IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
inet_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING,
NETCONFA_IFINDEX_ALL,
net->ipv4.devconf_all);
} }
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
......
...@@ -469,6 +469,8 @@ static int inet6_netconf_msgsize_devconf(int type) ...@@ -469,6 +469,8 @@ static int inet6_netconf_msgsize_devconf(int type)
/* type -1 is used for ALL */ /* type -1 is used for ALL */
if (type == -1 || type == NETCONFA_FORWARDING) if (type == -1 || type == NETCONFA_FORWARDING)
size += nla_total_size(4); size += nla_total_size(4);
if (type == -1 || type == NETCONFA_MC_FORWARDING)
size += nla_total_size(4);
return size; return size;
} }
...@@ -496,6 +498,10 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, ...@@ -496,6 +498,10 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
if ((type == -1 || type == NETCONFA_FORWARDING) && if ((type == -1 || type == NETCONFA_FORWARDING) &&
nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0) nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0)
goto nla_put_failure; goto nla_put_failure;
if ((type == -1 || type == NETCONFA_MC_FORWARDING) &&
nla_put_s32(skb, NETCONFA_MC_FORWARDING,
devconf->mc_forwarding) < 0)
goto nla_put_failure;
return nlmsg_end(skb, nlh); return nlmsg_end(skb, nlh);
...@@ -504,7 +510,7 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, ...@@ -504,7 +510,7 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
return -EMSGSIZE; return -EMSGSIZE;
} }
static void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex, void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
struct ipv6_devconf *devconf) struct ipv6_devconf *devconf)
{ {
struct sk_buff *skb; struct sk_buff *skb;
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <linux/netfilter_ipv6.h> #include <linux/netfilter_ipv6.h>
#include <linux/export.h> #include <linux/export.h>
#include <net/ip6_checksum.h> #include <net/ip6_checksum.h>
#include <linux/netconf.h>
struct mr6_table { struct mr6_table {
struct list_head list; struct list_head list;
...@@ -805,8 +806,12 @@ static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head) ...@@ -805,8 +806,12 @@ static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head)
dev_set_allmulti(dev, -1); dev_set_allmulti(dev, -1);
in6_dev = __in6_dev_get(dev); in6_dev = __in6_dev_get(dev);
if (in6_dev) if (in6_dev) {
in6_dev->cnf.mc_forwarding--; in6_dev->cnf.mc_forwarding--;
inet6_netconf_notify_devconf(dev_net(dev),
NETCONFA_MC_FORWARDING,
dev->ifindex, &in6_dev->cnf);
}
if (v->flags & MIFF_REGISTER) if (v->flags & MIFF_REGISTER)
unregister_netdevice_queue(dev, head); unregister_netdevice_queue(dev, head);
...@@ -958,8 +963,12 @@ static int mif6_add(struct net *net, struct mr6_table *mrt, ...@@ -958,8 +963,12 @@ static int mif6_add(struct net *net, struct mr6_table *mrt,
} }
in6_dev = __in6_dev_get(dev); in6_dev = __in6_dev_get(dev);
if (in6_dev) if (in6_dev) {
in6_dev->cnf.mc_forwarding++; in6_dev->cnf.mc_forwarding++;
inet6_netconf_notify_devconf(dev_net(dev),
NETCONFA_MC_FORWARDING,
dev->ifindex, &in6_dev->cnf);
}
/* /*
* Fill in the VIF structures * Fill in the VIF structures
...@@ -1513,6 +1522,9 @@ static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk) ...@@ -1513,6 +1522,9 @@ static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
if (likely(mrt->mroute6_sk == NULL)) { if (likely(mrt->mroute6_sk == NULL)) {
mrt->mroute6_sk = sk; mrt->mroute6_sk = sk;
net->ipv6.devconf_all->mc_forwarding++; net->ipv6.devconf_all->mc_forwarding++;
inet6_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING,
NETCONFA_IFINDEX_ALL,
net->ipv6.devconf_all);
} }
else else
err = -EADDRINUSE; err = -EADDRINUSE;
...@@ -1535,6 +1547,10 @@ int ip6mr_sk_done(struct sock *sk) ...@@ -1535,6 +1547,10 @@ int ip6mr_sk_done(struct sock *sk)
write_lock_bh(&mrt_lock); write_lock_bh(&mrt_lock);
mrt->mroute6_sk = NULL; mrt->mroute6_sk = NULL;
net->ipv6.devconf_all->mc_forwarding--; net->ipv6.devconf_all->mc_forwarding--;
inet6_netconf_notify_devconf(net,
NETCONFA_MC_FORWARDING,
NETCONFA_IFINDEX_ALL,
net->ipv6.devconf_all);
write_unlock_bh(&mrt_lock); write_unlock_bh(&mrt_lock);
mroute_clean_tables(mrt); mroute_clean_tables(mrt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment