diff options
author | Greg Rose <gregory.v.rose@intel.com> | 2011-06-09 21:27:09 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-06-09 23:38:07 -0400 |
commit | c7ac8679bec9397afe8918f788cbcef88c38da54 (patch) | |
tree | c152712de4c997ea79252ef9ac72aaedb8f88c18 /net/core | |
parent | 929dd047720785f099e12113780b3d7914ce6d9f (diff) |
rtnetlink: Compute and store minimum ifinfo dump size
The message size allocated for rtnl ifinfo dumps was limited to
a single page. This is not enough for additional interface info
available with devices that support SR-IOV and caused a bug in
which VF info would not be displayed if more than approximately
40 VFs were created per interface.
Implement a new function pointer for the rtnl_register service that will
calculate the amount of data required for the ifinfo dump and allocate
enough data to satisfy the request.
Signed-off-by: Greg Rose <gregory.v.rose@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/fib_rules.c | 6 | ||||
-rw-r--r-- | net/core/neighbour.c | 11 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 60 |
3 files changed, 58 insertions, 19 deletions
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 008dc70b064b..e7ab0c0285b5 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -740,9 +740,9 @@ static struct pernet_operations fib_rules_net_ops = { | |||
740 | static int __init fib_rules_init(void) | 740 | static int __init fib_rules_init(void) |
741 | { | 741 | { |
742 | int err; | 742 | int err; |
743 | rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL); | 743 | rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL, NULL); |
744 | rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL); | 744 | rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL, NULL); |
745 | rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule); | 745 | rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule, NULL); |
746 | 746 | ||
747 | err = register_pernet_subsys(&fib_rules_net_ops); | 747 | err = register_pernet_subsys(&fib_rules_net_ops); |
748 | if (err < 0) | 748 | if (err < 0) |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 799f06e03a22..ceb505b1507c 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -2909,12 +2909,13 @@ EXPORT_SYMBOL(neigh_sysctl_unregister); | |||
2909 | 2909 | ||
2910 | static int __init neigh_init(void) | 2910 | static int __init neigh_init(void) |
2911 | { | 2911 | { |
2912 | rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL); | 2912 | rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL); |
2913 | rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL); | 2913 | rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL); |
2914 | rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info); | 2914 | rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL); |
2915 | 2915 | ||
2916 | rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info); | 2916 | rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info, |
2917 | rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL); | 2917 | NULL); |
2918 | rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL); | ||
2918 | 2919 | ||
2919 | return 0; | 2920 | return 0; |
2920 | } | 2921 | } |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index abd936d8a716..a798fc6f2aa1 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -56,9 +56,11 @@ | |||
56 | struct rtnl_link { | 56 | struct rtnl_link { |
57 | rtnl_doit_func doit; | 57 | rtnl_doit_func doit; |
58 | rtnl_dumpit_func dumpit; | 58 | rtnl_dumpit_func dumpit; |
59 | rtnl_calcit_func calcit; | ||
59 | }; | 60 | }; |
60 | 61 | ||
61 | static DEFINE_MUTEX(rtnl_mutex); | 62 | static DEFINE_MUTEX(rtnl_mutex); |
63 | static u16 min_ifinfo_dump_size; | ||
62 | 64 | ||
63 | void rtnl_lock(void) | 65 | void rtnl_lock(void) |
64 | { | 66 | { |
@@ -144,12 +146,28 @@ static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex) | |||
144 | return tab ? tab[msgindex].dumpit : NULL; | 146 | return tab ? tab[msgindex].dumpit : NULL; |
145 | } | 147 | } |
146 | 148 | ||
149 | static rtnl_calcit_func rtnl_get_calcit(int protocol, int msgindex) | ||
150 | { | ||
151 | struct rtnl_link *tab; | ||
152 | |||
153 | if (protocol <= RTNL_FAMILY_MAX) | ||
154 | tab = rtnl_msg_handlers[protocol]; | ||
155 | else | ||
156 | tab = NULL; | ||
157 | |||
158 | if (tab == NULL || tab[msgindex].calcit == NULL) | ||
159 | tab = rtnl_msg_handlers[PF_UNSPEC]; | ||
160 | |||
161 | return tab ? tab[msgindex].calcit : NULL; | ||
162 | } | ||
163 | |||
147 | /** | 164 | /** |
148 | * __rtnl_register - Register a rtnetlink message type | 165 | * __rtnl_register - Register a rtnetlink message type |
149 | * @protocol: Protocol family or PF_UNSPEC | 166 | * @protocol: Protocol family or PF_UNSPEC |
150 | * @msgtype: rtnetlink message type | 167 | * @msgtype: rtnetlink message type |
151 | * @doit: Function pointer called for each request message | 168 | * @doit: Function pointer called for each request message |
152 | * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message | 169 | * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message |
170 | * @calcit: Function pointer to calc size of dump message | ||
153 | * | 171 | * |
154 | * Registers the specified function pointers (at least one of them has | 172 | * Registers the specified function pointers (at least one of them has |
155 | * to be non-NULL) to be called whenever a request message for the | 173 | * to be non-NULL) to be called whenever a request message for the |
@@ -162,7 +180,8 @@ static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex) | |||
162 | * Returns 0 on success or a negative error code. | 180 | * Returns 0 on success or a negative error code. |
163 | */ | 181 | */ |
164 | int __rtnl_register(int protocol, int msgtype, | 182 | int __rtnl_register(int protocol, int msgtype, |
165 | rtnl_doit_func doit, rtnl_dumpit_func dumpit) | 183 | rtnl_doit_func doit, rtnl_dumpit_func dumpit, |
184 | rtnl_calcit_func calcit) | ||
166 | { | 185 | { |
167 | struct rtnl_link *tab; | 186 | struct rtnl_link *tab; |
168 | int msgindex; | 187 | int msgindex; |
@@ -185,6 +204,9 @@ int __rtnl_register(int protocol, int msgtype, | |||
185 | if (dumpit) | 204 | if (dumpit) |
186 | tab[msgindex].dumpit = dumpit; | 205 | tab[msgindex].dumpit = dumpit; |
187 | 206 | ||
207 | if (calcit) | ||
208 | tab[msgindex].calcit = calcit; | ||
209 | |||
188 | return 0; | 210 | return 0; |
189 | } | 211 | } |
190 | EXPORT_SYMBOL_GPL(__rtnl_register); | 212 | EXPORT_SYMBOL_GPL(__rtnl_register); |
@@ -199,9 +221,10 @@ EXPORT_SYMBOL_GPL(__rtnl_register); | |||
199 | * of memory implies no sense in continuing. | 221 | * of memory implies no sense in continuing. |
200 | */ | 222 | */ |
201 | void rtnl_register(int protocol, int msgtype, | 223 | void rtnl_register(int protocol, int msgtype, |
202 | rtnl_doit_func doit, rtnl_dumpit_func dumpit) | 224 | rtnl_doit_func doit, rtnl_dumpit_func dumpit, |
225 | rtnl_calcit_func calcit) | ||
203 | { | 226 | { |
204 | if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0) | 227 | if (__rtnl_register(protocol, msgtype, doit, dumpit, calcit) < 0) |
205 | panic("Unable to register rtnetlink message handler, " | 228 | panic("Unable to register rtnetlink message handler, " |
206 | "protocol = %d, message type = %d\n", | 229 | "protocol = %d, message type = %d\n", |
207 | protocol, msgtype); | 230 | protocol, msgtype); |
@@ -1818,6 +1841,11 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
1818 | return err; | 1841 | return err; |
1819 | } | 1842 | } |
1820 | 1843 | ||
1844 | static u16 rtnl_calcit(struct sk_buff *skb) | ||
1845 | { | ||
1846 | return min_ifinfo_dump_size; | ||
1847 | } | ||
1848 | |||
1821 | static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | 1849 | static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) |
1822 | { | 1850 | { |
1823 | int idx; | 1851 | int idx; |
@@ -1847,11 +1875,14 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) | |||
1847 | struct net *net = dev_net(dev); | 1875 | struct net *net = dev_net(dev); |
1848 | struct sk_buff *skb; | 1876 | struct sk_buff *skb; |
1849 | int err = -ENOBUFS; | 1877 | int err = -ENOBUFS; |
1878 | size_t if_info_size; | ||
1850 | 1879 | ||
1851 | skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); | 1880 | skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), GFP_KERNEL); |
1852 | if (skb == NULL) | 1881 | if (skb == NULL) |
1853 | goto errout; | 1882 | goto errout; |
1854 | 1883 | ||
1884 | min_ifinfo_dump_size = max_t(u16, if_info_size, min_ifinfo_dump_size); | ||
1885 | |||
1855 | err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0); | 1886 | err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0); |
1856 | if (err < 0) { | 1887 | if (err < 0) { |
1857 | /* -EMSGSIZE implies BUG in if_nlmsg_size() */ | 1888 | /* -EMSGSIZE implies BUG in if_nlmsg_size() */ |
@@ -1902,14 +1933,20 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1902 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { | 1933 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |
1903 | struct sock *rtnl; | 1934 | struct sock *rtnl; |
1904 | rtnl_dumpit_func dumpit; | 1935 | rtnl_dumpit_func dumpit; |
1936 | rtnl_calcit_func calcit; | ||
1937 | u16 min_dump_alloc = 0; | ||
1905 | 1938 | ||
1906 | dumpit = rtnl_get_dumpit(family, type); | 1939 | dumpit = rtnl_get_dumpit(family, type); |
1907 | if (dumpit == NULL) | 1940 | if (dumpit == NULL) |
1908 | return -EOPNOTSUPP; | 1941 | return -EOPNOTSUPP; |
1942 | calcit = rtnl_get_calcit(family, type); | ||
1943 | if (calcit) | ||
1944 | min_dump_alloc = calcit(skb); | ||
1909 | 1945 | ||
1910 | __rtnl_unlock(); | 1946 | __rtnl_unlock(); |
1911 | rtnl = net->rtnl; | 1947 | rtnl = net->rtnl; |
1912 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); | 1948 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, |
1949 | NULL, min_dump_alloc); | ||
1913 | rtnl_lock(); | 1950 | rtnl_lock(); |
1914 | return err; | 1951 | return err; |
1915 | } | 1952 | } |
@@ -2019,12 +2056,13 @@ void __init rtnetlink_init(void) | |||
2019 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); | 2056 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); |
2020 | register_netdevice_notifier(&rtnetlink_dev_notifier); | 2057 | register_netdevice_notifier(&rtnetlink_dev_notifier); |
2021 | 2058 | ||
2022 | rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo); | 2059 | rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, |
2023 | rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL); | 2060 | rtnl_dump_ifinfo, rtnl_calcit); |
2024 | rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL); | 2061 | rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL, NULL); |
2025 | rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL); | 2062 | rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL, NULL); |
2063 | rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL, NULL); | ||
2026 | 2064 | ||
2027 | rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all); | 2065 | rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all, NULL); |
2028 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all); | 2066 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, NULL); |
2029 | } | 2067 | } |
2030 | 2068 | ||