aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorThomas Graf <tgraf@infradead.org>2010-11-15 23:33:57 -0500
committerDavid S. Miller <davem@davemloft.net>2010-11-17 14:28:26 -0500
commitb382b191ea9e9ccefc437433d23befe91f4a8925 (patch)
tree182ccdcb1cbb2258e2a951aa32674426547c922b /net/ipv6
parent9f0f7272ac9506f4c8c05cc597b7e376b0b9f3e4 (diff)
ipv6: AF_INET6 link address family
IPv6 already exposes some address family data via netlink in the IFLA_PROTINFO attribute if RTM_GETLINK request is sent with the address family set to AF_INET6. We take over this format and reuse all the code. Signed-off-by: Thomas Graf <tgraf@infradead.org> Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c122
1 files changed, 89 insertions, 33 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index aaa3ca448d08..470e7acb91df 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3831,6 +3831,15 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
3831 array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; 3831 array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
3832} 3832}
3833 3833
3834static inline size_t inet6_ifla6_size(void)
3835{
3836 return nla_total_size(4) /* IFLA_INET6_FLAGS */
3837 + nla_total_size(sizeof(struct ifla_cacheinfo))
3838 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
3839 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
3840 + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */
3841}
3842
3834static inline size_t inet6_if_nlmsg_size(void) 3843static inline size_t inet6_if_nlmsg_size(void)
3835{ 3844{
3836 return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 3845 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
@@ -3838,13 +3847,7 @@ static inline size_t inet6_if_nlmsg_size(void)
3838 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ 3847 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
3839 + nla_total_size(4) /* IFLA_MTU */ 3848 + nla_total_size(4) /* IFLA_MTU */
3840 + nla_total_size(4) /* IFLA_LINK */ 3849 + nla_total_size(4) /* IFLA_LINK */
3841 + nla_total_size( /* IFLA_PROTINFO */ 3850 + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */
3842 nla_total_size(4) /* IFLA_INET6_FLAGS */
3843 + nla_total_size(sizeof(struct ifla_cacheinfo))
3844 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
3845 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
3846 + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */
3847 );
3848} 3851}
3849 3852
3850static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, 3853static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
@@ -3891,15 +3894,76 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
3891 } 3894 }
3892} 3895}
3893 3896
3897static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
3898{
3899 struct nlattr *nla;
3900 struct ifla_cacheinfo ci;
3901
3902 NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags);
3903
3904 ci.max_reasm_len = IPV6_MAXPLEN;
3905 ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100
3906 + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
3907 ci.reachable_time = idev->nd_parms->reachable_time;
3908 ci.retrans_time = idev->nd_parms->retrans_time;
3909 NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
3910
3911 nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
3912 if (nla == NULL)
3913 goto nla_put_failure;
3914 ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
3915
3916 /* XXX - MC not implemented */
3917
3918 nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
3919 if (nla == NULL)
3920 goto nla_put_failure;
3921 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
3922
3923 nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
3924 if (nla == NULL)
3925 goto nla_put_failure;
3926 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
3927
3928 return 0;
3929
3930nla_put_failure:
3931 return -EMSGSIZE;
3932}
3933
3934static size_t inet6_get_link_af_size(const struct net_device *dev)
3935{
3936 if (!__in6_dev_get(dev))
3937 return 0;
3938
3939 return inet6_ifla6_size();
3940}
3941
3942static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
3943{
3944 struct inet6_dev *idev = __in6_dev_get(dev);
3945
3946 if (!idev)
3947 return -ENODATA;
3948
3949 if (inet6_fill_ifla6_attrs(skb, idev) < 0)
3950 return -EMSGSIZE;
3951
3952 return 0;
3953}
3954
3955static int inet6_parse_link_af(struct net_device *dev, const struct nlattr *nla)
3956{
3957 return -EOPNOTSUPP;
3958}
3959
3894static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 3960static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
3895 u32 pid, u32 seq, int event, unsigned int flags) 3961 u32 pid, u32 seq, int event, unsigned int flags)
3896{ 3962{
3897 struct net_device *dev = idev->dev; 3963 struct net_device *dev = idev->dev;
3898 struct nlattr *nla;
3899 struct ifinfomsg *hdr; 3964 struct ifinfomsg *hdr;
3900 struct nlmsghdr *nlh; 3965 struct nlmsghdr *nlh;
3901 void *protoinfo; 3966 void *protoinfo;
3902 struct ifla_cacheinfo ci;
3903 3967
3904 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); 3968 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
3905 if (nlh == NULL) 3969 if (nlh == NULL)
@@ -3926,31 +3990,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
3926 if (protoinfo == NULL) 3990 if (protoinfo == NULL)
3927 goto nla_put_failure; 3991 goto nla_put_failure;
3928 3992
3929 NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); 3993 if (inet6_fill_ifla6_attrs(skb, idev) < 0)
3930
3931 ci.max_reasm_len = IPV6_MAXPLEN;
3932 ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100
3933 + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
3934 ci.reachable_time = idev->nd_parms->reachable_time;
3935 ci.retrans_time = idev->nd_parms->retrans_time;
3936 NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
3937
3938 nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
3939 if (nla == NULL)
3940 goto nla_put_failure;
3941 ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
3942
3943 /* XXX - MC not implemented */
3944
3945 nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
3946 if (nla == NULL)
3947 goto nla_put_failure;
3948 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
3949
3950 nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
3951 if (nla == NULL)
3952 goto nla_put_failure; 3994 goto nla_put_failure;
3953 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
3954 3995
3955 nla_nest_end(skb, protoinfo); 3996 nla_nest_end(skb, protoinfo);
3956 return nlmsg_end(skb, nlh); 3997 return nlmsg_end(skb, nlh);
@@ -4621,6 +4662,13 @@ int unregister_inet6addr_notifier(struct notifier_block *nb)
4621} 4662}
4622EXPORT_SYMBOL(unregister_inet6addr_notifier); 4663EXPORT_SYMBOL(unregister_inet6addr_notifier);
4623 4664
4665static struct rtnl_af_ops inet6_ops = {
4666 .family = AF_INET6,
4667 .fill_link_af = inet6_fill_link_af,
4668 .get_link_af_size = inet6_get_link_af_size,
4669 .parse_link_af = inet6_parse_link_af,
4670};
4671
4624/* 4672/*
4625 * Init / cleanup code 4673 * Init / cleanup code
4626 */ 4674 */
@@ -4672,6 +4720,10 @@ int __init addrconf_init(void)
4672 4720
4673 addrconf_verify(0); 4721 addrconf_verify(0);
4674 4722
4723 err = rtnl_af_register(&inet6_ops);
4724 if (err < 0)
4725 goto errout_af;
4726
4675 err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); 4727 err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo);
4676 if (err < 0) 4728 if (err < 0)
4677 goto errout; 4729 goto errout;
@@ -4687,6 +4739,8 @@ int __init addrconf_init(void)
4687 4739
4688 return 0; 4740 return 0;
4689errout: 4741errout:
4742 rtnl_af_unregister(&inet6_ops);
4743errout_af:
4690 unregister_netdevice_notifier(&ipv6_dev_notf); 4744 unregister_netdevice_notifier(&ipv6_dev_notf);
4691errlo: 4745errlo:
4692 unregister_pernet_subsys(&addrconf_ops); 4746 unregister_pernet_subsys(&addrconf_ops);
@@ -4707,6 +4761,8 @@ void addrconf_cleanup(void)
4707 4761
4708 rtnl_lock(); 4762 rtnl_lock();
4709 4763
4764 __rtnl_af_unregister(&inet6_ops);
4765
4710 /* clean dev list */ 4766 /* clean dev list */
4711 for_each_netdev(&init_net, dev) { 4767 for_each_netdev(&init_net, dev) {
4712 if (__in6_dev_get(dev) == NULL) 4768 if (__in6_dev_get(dev) == NULL)