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

rtnl/ipv6: use netconf msg to advertise forwarding status

Signed-off-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d900082b
...@@ -592,6 +592,8 @@ enum rtnetlink_groups { ...@@ -592,6 +592,8 @@ enum rtnetlink_groups {
#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE #define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
RTNLGRP_DCB, RTNLGRP_DCB,
#define RTNLGRP_DCB RTNLGRP_DCB #define RTNLGRP_DCB RTNLGRP_DCB
RTNLGRP_IPV6_NETCONF,
#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
__RTNLGRP_MAX __RTNLGRP_MAX
}; };
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1) #define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
......
...@@ -81,6 +81,7 @@ ...@@ -81,6 +81,7 @@
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
#include <linux/if_tunnel.h> #include <linux/if_tunnel.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/netconf.h>
#ifdef CONFIG_IPV6_PRIVACY #ifdef CONFIG_IPV6_PRIVACY
#include <linux/random.h> #include <linux/random.h>
...@@ -460,6 +461,72 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev) ...@@ -460,6 +461,72 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
return idev; return idev;
} }
static int inet6_netconf_msgsize_devconf(int type)
{
int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
+ nla_total_size(4); /* NETCONFA_IFINDEX */
if (type == NETCONFA_FORWARDING)
size += nla_total_size(4);
return size;
}
static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
struct ipv6_devconf *devconf, u32 portid,
u32 seq, int event, unsigned int flags,
int type)
{
struct nlmsghdr *nlh;
struct netconfmsg *ncm;
nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
flags);
if (nlh == NULL)
return -EMSGSIZE;
ncm = nlmsg_data(nlh);
ncm->ncm_family = AF_INET6;
if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
goto nla_put_failure;
if (type == NETCONFA_FORWARDING &&
nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0)
goto nla_put_failure;
return nlmsg_end(skb, nlh);
nla_put_failure:
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}
static void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
struct ipv6_devconf *devconf)
{
struct sk_buff *skb;
int err = -ENOBUFS;
skb = nlmsg_new(inet6_netconf_msgsize_devconf(type), GFP_ATOMIC);
if (skb == NULL)
goto errout;
err = inet6_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
RTM_NEWNETCONF, 0, type);
if (err < 0) {
/* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
rtnl_notify(skb, net, 0, RTNLGRP_IPV6_NETCONF, NULL, GFP_ATOMIC);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err);
}
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static void dev_forward_change(struct inet6_dev *idev) static void dev_forward_change(struct inet6_dev *idev)
{ {
...@@ -486,6 +553,8 @@ static void dev_forward_change(struct inet6_dev *idev) ...@@ -486,6 +553,8 @@ static void dev_forward_change(struct inet6_dev *idev)
else else
addrconf_leave_anycast(ifa); addrconf_leave_anycast(ifa);
} }
inet6_netconf_notify_devconf(dev_net(dev), NETCONFA_FORWARDING,
dev->ifindex, &idev->cnf);
} }
...@@ -518,6 +587,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) ...@@ -518,6 +587,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)
*p = newf; *p = newf;
if (p == &net->ipv6.devconf_dflt->forwarding) { if (p == &net->ipv6.devconf_dflt->forwarding) {
if ((!newf) ^ (!old))
inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING,
NETCONFA_IFINDEX_DEFAULT,
net->ipv6.devconf_dflt);
rtnl_unlock(); rtnl_unlock();
return 0; return 0;
} }
...@@ -525,6 +598,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) ...@@ -525,6 +598,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)
if (p == &net->ipv6.devconf_all->forwarding) { if (p == &net->ipv6.devconf_all->forwarding) {
net->ipv6.devconf_dflt->forwarding = newf; net->ipv6.devconf_dflt->forwarding = newf;
addrconf_forward_change(net, newf); addrconf_forward_change(net, newf);
if ((!newf) ^ (!old))
inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING,
NETCONFA_IFINDEX_ALL,
net->ipv6.devconf_all);
} else if ((!newf) ^ (!old)) } else if ((!newf) ^ (!old))
dev_forward_change((struct inet6_dev *)table->extra1); dev_forward_change((struct inet6_dev *)table->extra1);
rtnl_unlock(); rtnl_unlock();
......
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