diff options
author | Thomas Graf <tgraf@infradead.org> | 2010-11-15 23:33:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-11-17 14:28:26 -0500 |
commit | b382b191ea9e9ccefc437433d23befe91f4a8925 (patch) | |
tree | 182ccdcb1cbb2258e2a951aa32674426547c922b /net/ipv6 | |
parent | 9f0f7272ac9506f4c8c05cc597b7e376b0b9f3e4 (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.c | 122 |
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 | ||
3834 | static 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 | |||
3834 | static inline size_t inet6_if_nlmsg_size(void) | 3843 | static 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 | ||
3850 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | 3853 | static 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 | ||
3897 | static 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 | |||
3930 | nla_put_failure: | ||
3931 | return -EMSGSIZE; | ||
3932 | } | ||
3933 | |||
3934 | static 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 | |||
3942 | static 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 | |||
3955 | static int inet6_parse_link_af(struct net_device *dev, const struct nlattr *nla) | ||
3956 | { | ||
3957 | return -EOPNOTSUPP; | ||
3958 | } | ||
3959 | |||
3894 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3960 | static 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 | } |
4622 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 4663 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
4623 | 4664 | ||
4665 | static 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; |
4689 | errout: | 4741 | errout: |
4742 | rtnl_af_unregister(&inet6_ops); | ||
4743 | errout_af: | ||
4690 | unregister_netdevice_notifier(&ipv6_dev_notf); | 4744 | unregister_netdevice_notifier(&ipv6_dev_notf); |
4691 | errlo: | 4745 | errlo: |
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) |