forked from mirrors/linux
		
	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>
			
			
This commit is contained in:
		
							parent
							
								
									ca7479ebbd
								
							
						
					
					
						commit
						9f0f7272ac
					
				
					 2 changed files with 83 additions and 0 deletions
				
			
		|  | @ -147,6 +147,14 @@ enum { | ||||||
| #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) | #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | enum { | ||||||
|  | 	IFLA_INET_UNSPEC, | ||||||
|  | 	IFLA_INET_CONF, | ||||||
|  | 	__IFLA_INET_MAX, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define IFLA_INET_MAX (__IFLA_INET_MAX - 1) | ||||||
|  | 
 | ||||||
| /* ifi_flags.
 | /* ifi_flags.
 | ||||||
| 
 | 
 | ||||||
|    IFF_* flags. |    IFF_* flags. | ||||||
|  |  | ||||||
|  | @ -1256,6 +1256,72 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, | ||||||
| 		rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); | 		rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static size_t inet_get_link_af_size(const struct net_device *dev) | ||||||
|  | { | ||||||
|  | 	struct in_device *in_dev = __in_dev_get_rcu(dev); | ||||||
|  | 
 | ||||||
|  | 	if (!in_dev) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | ||||||
|  | { | ||||||
|  | 	struct in_device *in_dev = __in_dev_get_rcu(dev); | ||||||
|  | 	struct nlattr *nla; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	if (!in_dev) | ||||||
|  | 		return -ENODATA; | ||||||
|  | 
 | ||||||
|  | 	nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4); | ||||||
|  | 	if (nla == NULL) | ||||||
|  | 		return -EMSGSIZE; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < IPV4_DEVCONF_MAX; i++) | ||||||
|  | 		((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i]; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { | ||||||
|  | 	[IFLA_INET_CONF]	= { .type = NLA_NESTED }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int inet_parse_link_af(struct net_device *dev, const struct nlattr *nla) | ||||||
|  | { | ||||||
|  | 	struct in_device *in_dev = __in_dev_get_rcu(dev); | ||||||
|  | 	struct nlattr *a, *tb[IFLA_INET_MAX+1]; | ||||||
|  | 	int err, rem; | ||||||
|  | 
 | ||||||
|  | 	if (!in_dev) | ||||||
|  | 		return -EOPNOTSUPP; | ||||||
|  | 
 | ||||||
|  | 	err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	if (tb[IFLA_INET_CONF]) { | ||||||
|  | 		nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { | ||||||
|  | 			int cfgid = nla_type(a); | ||||||
|  | 
 | ||||||
|  | 			if (nla_len(a) < 4) | ||||||
|  | 				return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 			if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) | ||||||
|  | 				return -EINVAL; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (tb[IFLA_INET_CONF]) { | ||||||
|  | 		nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) | ||||||
|  | 			ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_SYSCTL | #ifdef CONFIG_SYSCTL | ||||||
| 
 | 
 | ||||||
| static void devinet_copy_dflt_conf(struct net *net, int i) | static void devinet_copy_dflt_conf(struct net *net, int i) | ||||||
|  | @ -1619,6 +1685,13 @@ static __net_initdata struct pernet_operations devinet_ops = { | ||||||
| 	.exit = devinet_exit_net, | 	.exit = devinet_exit_net, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static struct rtnl_af_ops inet_af_ops = { | ||||||
|  | 	.family		  = AF_INET, | ||||||
|  | 	.fill_link_af	  = inet_fill_link_af, | ||||||
|  | 	.get_link_af_size = inet_get_link_af_size, | ||||||
|  | 	.parse_link_af	  = inet_parse_link_af, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| void __init devinet_init(void) | void __init devinet_init(void) | ||||||
| { | { | ||||||
| 	register_pernet_subsys(&devinet_ops); | 	register_pernet_subsys(&devinet_ops); | ||||||
|  | @ -1626,6 +1699,8 @@ void __init devinet_init(void) | ||||||
| 	register_gifconf(PF_INET, inet_gifconf); | 	register_gifconf(PF_INET, inet_gifconf); | ||||||
| 	register_netdevice_notifier(&ip_netdev_notifier); | 	register_netdevice_notifier(&ip_netdev_notifier); | ||||||
| 
 | 
 | ||||||
|  | 	rtnl_af_register(&inet_af_ops); | ||||||
|  | 
 | ||||||
| 	rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); | 	rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); | ||||||
| 	rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); | 	rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); | ||||||
| 	rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); | 	rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Thomas Graf
						Thomas Graf