Skip to content

Commit

Permalink
rtnl/ipv4: use netconf msg to advertise forwarding status
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Nicolas Dichtel authored and David S. Miller committed Oct 28, 2012
1 parent 76f8f6c commit edc9e74
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 4 deletions.
2 changes: 2 additions & 0 deletions include/uapi/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@ enum rtnetlink_groups {
#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
RTNLGRP_DCB,
#define RTNLGRP_DCB RTNLGRP_DCB
RTNLGRP_IPV4_NETCONF,
#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF
RTNLGRP_IPV6_NETCONF,
#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
__RTNLGRP_MAX
Expand Down
93 changes: 89 additions & 4 deletions net/ipv4/devinet.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include <linux/sysctl.h>
#endif
#include <linux/kmod.h>
#include <linux/netconf.h>

#include <net/arp.h>
#include <net/ip.h>
Expand Down Expand Up @@ -1442,6 +1443,73 @@ static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
return 0;
}

static int inet_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 inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
struct ipv4_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_INET;

if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
goto nla_put_failure;

if (type == NETCONFA_FORWARDING &&
nla_put_s32(skb, NETCONFA_FORWARDING,
IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
goto nla_put_failure;

return nlmsg_end(skb, nlh);

nla_put_failure:
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

static void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
struct ipv4_devconf *devconf)
{
struct sk_buff *skb;
int err = -ENOBUFS;

skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC);
if (skb == NULL)
goto errout;

err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
RTM_NEWNETCONF, 0, type);
if (err < 0) {
/* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_ATOMIC);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
}

#ifdef CONFIG_SYSCTL

static void devinet_copy_dflt_conf(struct net *net, int i)
Expand All @@ -1467,15 +1535,24 @@ static void inet_forward_change(struct net *net)

IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
NETCONFA_IFINDEX_ALL,
net->ipv4.devconf_all);
inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
NETCONFA_IFINDEX_DEFAULT,
net->ipv4.devconf_dflt);

for_each_netdev(net, dev) {
struct in_device *in_dev;
if (on)
dev_disable_lro(dev);
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev)
if (in_dev) {
IN_DEV_CONF_SET(in_dev, FORWARDING, on);
inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
dev->ifindex, &in_dev->cnf);
}
rcu_read_unlock();
}
}
Expand Down Expand Up @@ -1527,15 +1604,23 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
}
if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
inet_forward_change(net);
} else if (*valp) {
} else {
struct ipv4_devconf *cnf = ctl->extra1;
struct in_device *idev =
container_of(cnf, struct in_device, cnf);
dev_disable_lro(idev->dev);
if (*valp)
dev_disable_lro(idev->dev);
inet_netconf_notify_devconf(net,
NETCONFA_FORWARDING,
idev->dev->ifindex,
cnf);
}
rtnl_unlock();
rt_cache_flush(net);
}
} else
inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
NETCONFA_IFINDEX_DEFAULT,
net->ipv4.devconf_dflt);
}

return ret;
Expand Down

0 comments on commit edc9e74

Please sign in to comment.