diff options
author | Thomas Graf <tgraf@infradead.org> | 2010-11-15 23:32:48 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-11-17 14:28:25 -0500 |
commit | 9f0f7272ac9506f4c8c05cc597b7e376b0b9f3e4 (patch) | |
tree | d26f7c7e8f06313ffc8c0869935650f2b104ab58 /net/ipv4/devinet.c | |
parent | ca7479ebbd9f7621646bf2792cb7143647f035bb (diff) |
ipv4: AF_INET link address family
Implements the AF_INET link address family exposing the per
device configuration settings via netlink using the attribute
IFLA_INET_CONF.
The format of IFLA_INET_CONF differs depending on the direction
the attribute is sent. The attribute sent by the kernel consists
of a u32 array, basically a 1:1 copy of in_device->cnf.data[].
The attribute expected by the kernel must consist of a sequence
of nested u32 attributes, each representing a change request,
e.g.
[IFLA_INET_CONF] = {
[IPV4_DEVCONF_FORWARDING] = 1,
[IPV4_DEVCONF_NOXFRM] = 0,
}
libnl userspace API documentation and example available from:
http://www.infradead.org/~tgr/libnl/doc-git/group__link__inet.html
Signed-off-by: Thomas Graf <tgraf@infradead.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r-- | net/ipv4/devinet.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index dc94b0316b78..71afc26c2df8 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1256,6 +1256,72 @@ errout: | |||
1256 | rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); | 1256 | rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | static size_t inet_get_link_af_size(const struct net_device *dev) | ||
1260 | { | ||
1261 | struct in_device *in_dev = __in_dev_get_rcu(dev); | ||
1262 | |||
1263 | if (!in_dev) | ||
1264 | return 0; | ||
1265 | |||
1266 | return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */ | ||
1267 | } | ||
1268 | |||
1269 | static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | ||
1270 | { | ||
1271 | struct in_device *in_dev = __in_dev_get_rcu(dev); | ||
1272 | struct nlattr *nla; | ||
1273 | int i; | ||
1274 | |||
1275 | if (!in_dev) | ||
1276 | return -ENODATA; | ||
1277 | |||
1278 | nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4); | ||
1279 | if (nla == NULL) | ||
1280 | return -EMSGSIZE; | ||
1281 | |||
1282 | for (i = 0; i < IPV4_DEVCONF_MAX; i++) | ||
1283 | ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i]; | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { | ||
1289 | [IFLA_INET_CONF] = { .type = NLA_NESTED }, | ||
1290 | }; | ||
1291 | |||
1292 | static int inet_parse_link_af(struct net_device *dev, const struct nlattr *nla) | ||
1293 | { | ||
1294 | struct in_device *in_dev = __in_dev_get_rcu(dev); | ||
1295 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; | ||
1296 | int err, rem; | ||
1297 | |||
1298 | if (!in_dev) | ||
1299 | return -EOPNOTSUPP; | ||
1300 | |||
1301 | err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy); | ||
1302 | if (err < 0) | ||
1303 | return err; | ||
1304 | |||
1305 | if (tb[IFLA_INET_CONF]) { | ||
1306 | nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { | ||
1307 | int cfgid = nla_type(a); | ||
1308 | |||
1309 | if (nla_len(a) < 4) | ||
1310 | return -EINVAL; | ||
1311 | |||
1312 | if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) | ||
1313 | return -EINVAL; | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | if (tb[IFLA_INET_CONF]) { | ||
1318 | nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) | ||
1319 | ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a)); | ||
1320 | } | ||
1321 | |||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1259 | #ifdef CONFIG_SYSCTL | 1325 | #ifdef CONFIG_SYSCTL |
1260 | 1326 | ||
1261 | static void devinet_copy_dflt_conf(struct net *net, int i) | 1327 | static void devinet_copy_dflt_conf(struct net *net, int i) |
@@ -1619,6 +1685,13 @@ static __net_initdata struct pernet_operations devinet_ops = { | |||
1619 | .exit = devinet_exit_net, | 1685 | .exit = devinet_exit_net, |
1620 | }; | 1686 | }; |
1621 | 1687 | ||
1688 | static struct rtnl_af_ops inet_af_ops = { | ||
1689 | .family = AF_INET, | ||
1690 | .fill_link_af = inet_fill_link_af, | ||
1691 | .get_link_af_size = inet_get_link_af_size, | ||
1692 | .parse_link_af = inet_parse_link_af, | ||
1693 | }; | ||
1694 | |||
1622 | void __init devinet_init(void) | 1695 | void __init devinet_init(void) |
1623 | { | 1696 | { |
1624 | register_pernet_subsys(&devinet_ops); | 1697 | register_pernet_subsys(&devinet_ops); |
@@ -1626,6 +1699,8 @@ void __init devinet_init(void) | |||
1626 | register_gifconf(PF_INET, inet_gifconf); | 1699 | register_gifconf(PF_INET, inet_gifconf); |
1627 | register_netdevice_notifier(&ip_netdev_notifier); | 1700 | register_netdevice_notifier(&ip_netdev_notifier); |
1628 | 1701 | ||
1702 | rtnl_af_register(&inet_af_ops); | ||
1703 | |||
1629 | rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); | 1704 | rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); |
1630 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); | 1705 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); |
1631 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); | 1706 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); |