aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2012-10-25 18:28:52 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-28 19:05:00 -0400
commitedc9e748934cf406cab708ca5dda7bd3c0f0a1db (patch)
tree0c7e4b1aa6f747ca24f09bd4a8752032a4d22834 /net/ipv4
parent76f8f6cb76b110aaace90b6208b1ceb46bd78b7f (diff)
rtnl/ipv4: use netconf msg to advertise forwarding status
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/devinet.c93
1 files changed, 89 insertions, 4 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 2a6abc163ed2..020fdd2e6e19 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -55,6 +55,7 @@
55#include <linux/sysctl.h> 55#include <linux/sysctl.h>
56#endif 56#endif
57#include <linux/kmod.h> 57#include <linux/kmod.h>
58#include <linux/netconf.h>
58 59
59#include <net/arp.h> 60#include <net/arp.h>
60#include <net/ip.h> 61#include <net/ip.h>
@@ -1442,6 +1443,73 @@ static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1442 return 0; 1443 return 0;
1443} 1444}
1444 1445
1446static int inet_netconf_msgsize_devconf(int type)
1447{
1448 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1449 + nla_total_size(4); /* NETCONFA_IFINDEX */
1450
1451 if (type == NETCONFA_FORWARDING)
1452 size += nla_total_size(4);
1453
1454 return size;
1455}
1456
1457static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
1458 struct ipv4_devconf *devconf, u32 portid,
1459 u32 seq, int event, unsigned int flags,
1460 int type)
1461{
1462 struct nlmsghdr *nlh;
1463 struct netconfmsg *ncm;
1464
1465 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1466 flags);
1467 if (nlh == NULL)
1468 return -EMSGSIZE;
1469
1470 ncm = nlmsg_data(nlh);
1471 ncm->ncm_family = AF_INET;
1472
1473 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
1474 goto nla_put_failure;
1475
1476 if (type == NETCONFA_FORWARDING &&
1477 nla_put_s32(skb, NETCONFA_FORWARDING,
1478 IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
1479 goto nla_put_failure;
1480
1481 return nlmsg_end(skb, nlh);
1482
1483nla_put_failure:
1484 nlmsg_cancel(skb, nlh);
1485 return -EMSGSIZE;
1486}
1487
1488static void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
1489 struct ipv4_devconf *devconf)
1490{
1491 struct sk_buff *skb;
1492 int err = -ENOBUFS;
1493
1494 skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC);
1495 if (skb == NULL)
1496 goto errout;
1497
1498 err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
1499 RTM_NEWNETCONF, 0, type);
1500 if (err < 0) {
1501 /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
1502 WARN_ON(err == -EMSGSIZE);
1503 kfree_skb(skb);
1504 goto errout;
1505 }
1506 rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_ATOMIC);
1507 return;
1508errout:
1509 if (err < 0)
1510 rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err);
1511}
1512
1445#ifdef CONFIG_SYSCTL 1513#ifdef CONFIG_SYSCTL
1446 1514
1447static void devinet_copy_dflt_conf(struct net *net, int i) 1515static void devinet_copy_dflt_conf(struct net *net, int i)
@@ -1467,6 +1535,12 @@ static void inet_forward_change(struct net *net)
1467 1535
1468 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on; 1536 IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
1469 IPV4_DEVCONF_DFLT(net, FORWARDING) = on; 1537 IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
1538 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1539 NETCONFA_IFINDEX_ALL,
1540 net->ipv4.devconf_all);
1541 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1542 NETCONFA_IFINDEX_DEFAULT,
1543 net->ipv4.devconf_dflt);
1470 1544
1471 for_each_netdev(net, dev) { 1545 for_each_netdev(net, dev) {
1472 struct in_device *in_dev; 1546 struct in_device *in_dev;
@@ -1474,8 +1548,11 @@ static void inet_forward_change(struct net *net)
1474 dev_disable_lro(dev); 1548 dev_disable_lro(dev);
1475 rcu_read_lock(); 1549 rcu_read_lock();
1476 in_dev = __in_dev_get_rcu(dev); 1550 in_dev = __in_dev_get_rcu(dev);
1477 if (in_dev) 1551 if (in_dev) {
1478 IN_DEV_CONF_SET(in_dev, FORWARDING, on); 1552 IN_DEV_CONF_SET(in_dev, FORWARDING, on);
1553 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1554 dev->ifindex, &in_dev->cnf);
1555 }
1479 rcu_read_unlock(); 1556 rcu_read_unlock();
1480 } 1557 }
1481} 1558}
@@ -1527,15 +1604,23 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
1527 } 1604 }
1528 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) { 1605 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
1529 inet_forward_change(net); 1606 inet_forward_change(net);
1530 } else if (*valp) { 1607 } else {
1531 struct ipv4_devconf *cnf = ctl->extra1; 1608 struct ipv4_devconf *cnf = ctl->extra1;
1532 struct in_device *idev = 1609 struct in_device *idev =
1533 container_of(cnf, struct in_device, cnf); 1610 container_of(cnf, struct in_device, cnf);
1534 dev_disable_lro(idev->dev); 1611 if (*valp)
1612 dev_disable_lro(idev->dev);
1613 inet_netconf_notify_devconf(net,
1614 NETCONFA_FORWARDING,
1615 idev->dev->ifindex,
1616 cnf);
1535 } 1617 }
1536 rtnl_unlock(); 1618 rtnl_unlock();
1537 rt_cache_flush(net); 1619 rt_cache_flush(net);
1538 } 1620 } else
1621 inet_netconf_notify_devconf(net, NETCONFA_FORWARDING,
1622 NETCONFA_IFINDEX_DEFAULT,
1623 net->ipv4.devconf_dflt);
1539 } 1624 }
1540 1625
1541 return ret; 1626 return ret;