]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
rtnetlink: Compute and store minimum ifinfo dump size
authorGreg Rose <gregory.v.rose@intel.com>
Fri, 4 Jan 2013 00:32:54 +0000 (00:32 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Jan 2013 16:43:58 +0000 (08:43 -0800)
commit c7ac8679bec9397afe8918f788cbcef88c38da54 upstream.

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>
Cc: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
30 files changed:
drivers/infiniband/core/netlink.c
include/linux/netlink.h
include/net/rtnetlink.h
net/bridge/br_netlink.c
net/core/fib_rules.c
net/core/neighbour.c
net/core/rtnetlink.c
net/dcb/dcbnl.c
net/decnet/dn_dev.c
net/decnet/dn_fib.c
net/decnet/dn_route.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/inet_diag.c
net/ipv4/ipmr.c
net/ipv4/route.c
net/ipv6/addrconf.c
net/ipv6/addrlabel.c
net/ipv6/ip6_fib.c
net/ipv6/ip6mr.c
net/ipv6/route.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/nf_conntrack_netlink.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/phonet/pn_netlink.c
net/sched/act_api.c
net/sched/cls_api.c
net/sched/sch_api.c
net/xfrm/xfrm_user.c

index 4a5abaf0a25cedc23fd3d053765983a1f3166f37..9227f4acd79c7dd457a3188abb8cf327d458bd07 100644 (file)
@@ -148,7 +148,7 @@ static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                return -EINVAL;
                        return netlink_dump_start(nls, skb, nlh,
                                                  client->cb_table[op].dump,
-                                                 NULL);
+                                                 NULL, 0);
                }
        }
 
index a9dd89552f9c61e804249e5b21d2504251925f2f..fdd0188a167e66be30e54c18ab31c21ec5d4c762 100644 (file)
@@ -221,7 +221,8 @@ struct netlink_callback {
        int                     (*dump)(struct sk_buff * skb,
                                        struct netlink_callback *cb);
        int                     (*done)(struct netlink_callback *cb);
-       int                     family;
+       u16                     family;
+       u16                     min_dump_alloc;
        long                    args[6];
 };
 
@@ -259,7 +260,8 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
 extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
                              const struct nlmsghdr *nlh,
                              int (*dump)(struct sk_buff *skb, struct netlink_callback*),
-                             int (*done)(struct netlink_callback*));
+                             int (*done)(struct netlink_callback*),
+                             u16 min_dump_alloc);
 
 
 #define NL_NONROOT_RECV 0x1
index 4093ca78cf60f997e5c6a3e4eb845766ec56d6ef..678f1ffaf843e108718e4b3162caa246795a048f 100644 (file)
@@ -6,11 +6,14 @@
 
 typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, void *);
 typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);
+typedef u16 (*rtnl_calcit_func)(struct sk_buff *);
 
 extern int     __rtnl_register(int protocol, int msgtype,
-                               rtnl_doit_func, rtnl_dumpit_func);
+                               rtnl_doit_func, rtnl_dumpit_func,
+                               rtnl_calcit_func);
 extern void    rtnl_register(int protocol, int msgtype,
-                             rtnl_doit_func, rtnl_dumpit_func);
+                             rtnl_doit_func, rtnl_dumpit_func,
+                             rtnl_calcit_func);
 extern int     rtnl_unregister(int protocol, int msgtype);
 extern void    rtnl_unregister_all(int protocol);
 
index 71861a9c4008a15a21f0ca33445808aa8c051838..d372df23632e72ab2b99dd069467d741d448c2ee 100644 (file)
@@ -219,19 +219,24 @@ int __init br_netlink_init(void)
        if (err < 0)
                goto err1;
 
-       err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo);
+       err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL,
+                             br_dump_ifinfo, NULL);
        if (err)
                goto err2;
-       err = __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL);
+       err = __rtnl_register(PF_BRIDGE, RTM_SETLINK,
+                             br_rtm_setlink, NULL, NULL);
        if (err)
                goto err3;
-       err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL);
+       err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH,
+                             br_fdb_add, NULL, NULL);
        if (err)
                goto err3;
-       err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL);
+       err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH,
+                             br_fdb_delete, NULL, NULL);
        if (err)
                goto err3;
-       err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump);
+       err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH,
+                             NULL, br_fdb_dump, NULL);
        if (err)
                goto err3;
 
index f39ef5c6084b943c7cd69fd82b05072fb65b7ba5..3231b468bb7297ba2c278758f59d741976324556 100644 (file)
@@ -740,9 +740,9 @@ static struct pernet_operations fib_rules_net_ops = {
 static int __init fib_rules_init(void)
 {
        int err;
-       rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL);
-       rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL);
-       rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule);
+       rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule, NULL);
 
        err = register_pernet_subsys(&fib_rules_net_ops);
        if (err < 0)
index eb8857a5e93af2cef3f5c9966cac8a628a0c942b..34032f27c513f3bc81c320f00373b976c0520f1c 100644 (file)
@@ -2918,12 +2918,13 @@ EXPORT_SYMBOL(neigh_sysctl_unregister);
 
 static int __init neigh_init(void)
 {
-       rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL);
-       rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL);
-       rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info);
+       rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
 
-       rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info);
-       rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
+                     NULL);
+       rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
 
        return 0;
 }
index ac49ad519ca2091cf9e60983d89f9404afc270a1..848de7b612ef02eb937293d4d8495066e95b9313 100644 (file)
 struct rtnl_link {
        rtnl_doit_func          doit;
        rtnl_dumpit_func        dumpit;
+       rtnl_calcit_func        calcit;
 };
 
 static DEFINE_MUTEX(rtnl_mutex);
+static u16 min_ifinfo_dump_size;
 
 void rtnl_lock(void)
 {
@@ -144,12 +146,28 @@ static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex)
        return tab ? tab[msgindex].dumpit : NULL;
 }
 
+static rtnl_calcit_func rtnl_get_calcit(int protocol, int msgindex)
+{
+       struct rtnl_link *tab;
+
+       if (protocol <= RTNL_FAMILY_MAX)
+               tab = rtnl_msg_handlers[protocol];
+       else
+               tab = NULL;
+
+       if (tab == NULL || tab[msgindex].calcit == NULL)
+               tab = rtnl_msg_handlers[PF_UNSPEC];
+
+       return tab ? tab[msgindex].calcit : NULL;
+}
+
 /**
  * __rtnl_register - Register a rtnetlink message type
  * @protocol: Protocol family or PF_UNSPEC
  * @msgtype: rtnetlink message type
  * @doit: Function pointer called for each request message
  * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
+ * @calcit: Function pointer to calc size of dump message
  *
  * Registers the specified function pointers (at least one of them has
  * 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)
  * Returns 0 on success or a negative error code.
  */
 int __rtnl_register(int protocol, int msgtype,
-                   rtnl_doit_func doit, rtnl_dumpit_func dumpit)
+                   rtnl_doit_func doit, rtnl_dumpit_func dumpit,
+                   rtnl_calcit_func calcit)
 {
        struct rtnl_link *tab;
        int msgindex;
@@ -185,6 +204,9 @@ int __rtnl_register(int protocol, int msgtype,
        if (dumpit)
                tab[msgindex].dumpit = dumpit;
 
+       if (calcit)
+               tab[msgindex].calcit = calcit;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(__rtnl_register);
@@ -199,9 +221,10 @@ EXPORT_SYMBOL_GPL(__rtnl_register);
  * of memory implies no sense in continuing.
  */
 void rtnl_register(int protocol, int msgtype,
-                  rtnl_doit_func doit, rtnl_dumpit_func dumpit)
+                  rtnl_doit_func doit, rtnl_dumpit_func dumpit,
+                  rtnl_calcit_func calcit)
 {
-       if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0)
+       if (__rtnl_register(protocol, msgtype, doit, dumpit, calcit) < 0)
                panic("Unable to register rtnetlink message handler, "
                      "protocol = %d, message type = %d\n",
                      protocol, msgtype);
@@ -1825,6 +1848,11 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
        return err;
 }
 
+static u16 rtnl_calcit(struct sk_buff *skb)
+{
+       return min_ifinfo_dump_size;
+}
+
 static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
 {
        int idx;
@@ -1854,11 +1882,14 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
        struct net *net = dev_net(dev);
        struct sk_buff *skb;
        int err = -ENOBUFS;
+       size_t if_info_size;
 
-       skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
+       skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), GFP_KERNEL);
        if (skb == NULL)
                goto errout;
 
+       min_ifinfo_dump_size = max_t(u16, if_info_size, min_ifinfo_dump_size);
+
        err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0);
        if (err < 0) {
                /* -EMSGSIZE implies BUG in if_nlmsg_size() */
@@ -1909,14 +1940,20 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
                struct sock *rtnl;
                rtnl_dumpit_func dumpit;
+               rtnl_calcit_func calcit;
+               u16 min_dump_alloc = 0;
 
                dumpit = rtnl_get_dumpit(family, type);
                if (dumpit == NULL)
                        return -EOPNOTSUPP;
+               calcit = rtnl_get_calcit(family, type);
+               if (calcit)
+                       min_dump_alloc = calcit(skb);
 
                __rtnl_unlock();
                rtnl = net->rtnl;
-               err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+               err = netlink_dump_start(rtnl, skb, nlh, dumpit,
+                                        NULL, min_dump_alloc);
                rtnl_lock();
                return err;
        }
@@ -2026,12 +2063,13 @@ void __init rtnetlink_init(void)
        netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
        register_netdevice_notifier(&rtnetlink_dev_notifier);
 
-       rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo);
-       rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL);
-       rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL);
-       rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink,
+                     rtnl_dump_ifinfo, rtnl_calcit);
+       rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL, NULL);
 
-       rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all);
-       rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all);
+       rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, NULL);
 }
 
index 3609eacaf4cedd332cf11e50a7af5096cc45bc26..ed1bb8c65a9e05c27ed340b157252974b6fffe9c 100644 (file)
@@ -1819,8 +1819,8 @@ static int __init dcbnl_init(void)
 {
        INIT_LIST_HEAD(&dcb_app_list);
 
-       rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
-       rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL);
 
        return 0;
 }
index cf26ac74a18827c714020b0b81d5d911f9391828..3780fd6e7bfe0fbcfeaeb7dfc53c4a4281e62282 100644 (file)
@@ -1414,9 +1414,9 @@ void __init dn_dev_init(void)
 
        dn_dev_devices_on();
 
-       rtnl_register(PF_DECnet, RTM_NEWADDR, dn_nl_newaddr, NULL);
-       rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL);
-       rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr);
+       rtnl_register(PF_DECnet, RTM_NEWADDR, dn_nl_newaddr, NULL, NULL);
+       rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL, NULL);
+       rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr, NULL);
 
        proc_net_fops_create(&init_net, "decnet_dev", S_IRUGO, &dn_dev_seq_fops);
 
index 1c74ed36ce8f9e81d827fe511699478a246ac9b6..104324d6d5355f93dcce6a7b7b905c31d1106a63 100644 (file)
@@ -763,8 +763,8 @@ void __init dn_fib_init(void)
 
        register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
 
-       rtnl_register(PF_DECnet, RTM_NEWROUTE, dn_fib_rtm_newroute, NULL);
-       rtnl_register(PF_DECnet, RTM_DELROUTE, dn_fib_rtm_delroute, NULL);
+       rtnl_register(PF_DECnet, RTM_NEWROUTE, dn_fib_rtm_newroute, NULL, NULL);
+       rtnl_register(PF_DECnet, RTM_DELROUTE, dn_fib_rtm_delroute, NULL, NULL);
 }
 
 
index b91b60363c3926ddf7ac3d4626b5f52ce77d0802..82d62507b794bee397ceef4f8fbeb33311a02583 100644 (file)
@@ -1843,10 +1843,11 @@ void __init dn_route_init(void)
        proc_net_fops_create(&init_net, "decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops);
 
 #ifdef CONFIG_DECNET_ROUTER
-       rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute, dn_fib_dump);
+       rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute,
+                     dn_fib_dump, NULL);
 #else
        rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute,
-                     dn_cache_dump);
+                     dn_cache_dump, NULL);
 #endif
 }
 
index 7d7fb20b0a12494bdabcd4baa5a57c527f80589e..070f214b886512cae4ff0f69ba70f051dd5c05da 100644 (file)
@@ -1838,8 +1838,8 @@ void __init devinet_init(void)
 
        rtnl_af_register(&inet_af_ops);
 
-       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_GETADDR, NULL, inet_dump_ifaddr);
+       rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
+       rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
+       rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
 }
 
index 22524716fe7063c7cb0861bcce0dfba92f4effab..92fc5f69f5da1c36aff62213d0c6bca358e624f7 100644 (file)
@@ -1124,9 +1124,9 @@ static struct pernet_operations fib_net_ops = {
 
 void __init ip_fib_init(void)
 {
-       rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL);
-       rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL);
-       rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib);
+       rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
+       rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
+       rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
 
        register_pernet_subsys(&fib_net_ops);
        register_netdevice_notifier(&fib_netdev_notifier);
index 3267d389843794e0b481f05c22021e905fc6e6d1..389a2e6a17fd84f67df22f57bbedbc8e211bded6 100644 (file)
@@ -869,7 +869,7 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                }
 
                return netlink_dump_start(idiagnl, skb, nlh,
-                                         inet_diag_dump, NULL);
+                                         inet_diag_dump, NULL, 0);
        }
 
        return inet_diag_get_exact(skb, nlh);
index ec7d8e7ea0df8900f7c4407878af883e80248f1f..dc8971459cdcaab0fdde4469aea9da331e374fba 100644 (file)
@@ -2554,7 +2554,8 @@ int __init ip_mr_init(void)
                goto add_proto_fail;
        }
 #endif
-       rtnl_register(RTNL_FAMILY_IPMR, RTM_GETROUTE, NULL, ipmr_rtm_dumproute);
+       rtnl_register(RTNL_FAMILY_IPMR, RTM_GETROUTE,
+                     NULL, ipmr_rtm_dumproute, NULL);
        return 0;
 
 #ifdef CONFIG_IP_PIMSM_V2
index 5ff2614706e73b52a4ac906343c7a9552c5113f1..0428b64ec400214d51833269cb78bca13498a372 100644 (file)
@@ -3454,7 +3454,7 @@ int __init ip_rt_init(void)
        xfrm_init();
        xfrm4_init(ip_rt_max_size);
 #endif
-       rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL);
+       rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL, NULL);
 
 #ifdef CONFIG_SYSCTL
        register_pernet_subsys(&sysctl_route_ops);
index 70d6a7fff10838bf7c47395b3f0ebfa4f0e4cbca..e845c0cb9631abc226a63e0e70ac42154f3e044e 100644 (file)
@@ -4694,16 +4694,20 @@ int __init addrconf_init(void)
        if (err < 0)
                goto errout_af;
 
-       err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo);
+       err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo,
+                             NULL);
        if (err < 0)
                goto errout;
 
        /* Only the first call to __rtnl_register can fail */
-       __rtnl_register(PF_INET6, RTM_NEWADDR, inet6_rtm_newaddr, NULL);
-       __rtnl_register(PF_INET6, RTM_DELADDR, inet6_rtm_deladdr, NULL);
-       __rtnl_register(PF_INET6, RTM_GETADDR, inet6_rtm_getaddr, inet6_dump_ifaddr);
-       __rtnl_register(PF_INET6, RTM_GETMULTICAST, NULL, inet6_dump_ifmcaddr);
-       __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, inet6_dump_ifacaddr);
+       __rtnl_register(PF_INET6, RTM_NEWADDR, inet6_rtm_newaddr, NULL, NULL);
+       __rtnl_register(PF_INET6, RTM_DELADDR, inet6_rtm_deladdr, NULL, NULL);
+       __rtnl_register(PF_INET6, RTM_GETADDR, inet6_rtm_getaddr,
+                       inet6_dump_ifaddr, NULL);
+       __rtnl_register(PF_INET6, RTM_GETMULTICAST, NULL,
+                       inet6_dump_ifmcaddr, NULL);
+       __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL,
+                       inet6_dump_ifacaddr, NULL);
 
        ipv6_addr_label_rtnl_register();
 
index c8993e5a337c25dd2dbe85f182a137dd82386c5d..2d8ddba9ee58274413a8b860f1116e1a5897a2c1 100644 (file)
@@ -592,8 +592,11 @@ out:
 
 void __init ipv6_addr_label_rtnl_register(void)
 {
-       __rtnl_register(PF_INET6, RTM_NEWADDRLABEL, ip6addrlbl_newdel, NULL);
-       __rtnl_register(PF_INET6, RTM_DELADDRLABEL, ip6addrlbl_newdel, NULL);
-       __rtnl_register(PF_INET6, RTM_GETADDRLABEL, ip6addrlbl_get, ip6addrlbl_dump);
+       __rtnl_register(PF_INET6, RTM_NEWADDRLABEL, ip6addrlbl_newdel,
+                       NULL, NULL);
+       __rtnl_register(PF_INET6, RTM_DELADDRLABEL, ip6addrlbl_newdel,
+                       NULL, NULL);
+       __rtnl_register(PF_INET6, RTM_GETADDRLABEL, ip6addrlbl_get,
+                       ip6addrlbl_dump, NULL);
 }
 
index 0f9b37a1c1d4025e2e7076a5bf2d12848dfec39d..320d91d20ad7ddfd981cee92161482f218c225b4 100644 (file)
@@ -1586,7 +1586,8 @@ int __init fib6_init(void)
        if (ret)
                goto out_kmem_cache_create;
 
-       ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
+       ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib,
+                             NULL);
        if (ret)
                goto out_unregister_subsys;
 out:
index 86e3cc10fc2e44b38250e2142f9cd3fd79928bf5..def0538e24139c02e74fe466d1ca3f877fa1848a 100644 (file)
@@ -1356,7 +1356,8 @@ int __init ip6_mr_init(void)
                goto add_proto_fail;
        }
 #endif
-       rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL, ip6mr_rtm_dumproute);
+       rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL,
+                     ip6mr_rtm_dumproute, NULL);
        return 0;
 #ifdef CONFIG_IPV6_PIMSM_V2
 add_proto_fail:
index da056c8917ed7ba4da304740ae3ce716c015692e..550fec3c9abf8783286c279961e1939b2329f283 100644 (file)
@@ -2956,9 +2956,9 @@ int __init ip6_route_init(void)
                goto fib6_rules_init;
 
        ret = -ENOBUFS;
-       if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL) ||
-           __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL) ||
-           __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
+       if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
+           __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
+           __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
                goto out_register_late_subsys;
 
        ret = register_netdevice_notifier(&ip6_route_dev_notifier);
index 42aa64b6b0b1b6c7ae87dbe7831776ea2d345366..ee37ae5de0939e2602468429ca2deeb658b98d2c 100644 (file)
@@ -1120,7 +1120,7 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
 
        return netlink_dump_start(ctnl, skb, nlh,
                                  ip_set_dump_start,
-                                 ip_set_dump_done);
+                                 ip_set_dump_done, 0);
 }
 
 /* Add, del and test */
index 482e90c6185087f2827b9f27448c74ac87eb0ef6..7dec88a1755b9fddcd1fb9d03c66fd54c396eac6 100644 (file)
@@ -970,7 +970,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
 
        if (nlh->nlmsg_flags & NLM_F_DUMP)
                return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table,
-                                         ctnetlink_done);
+                                         ctnetlink_done, 0);
 
        err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
        if (err < 0)
@@ -1840,7 +1840,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
        if (nlh->nlmsg_flags & NLM_F_DUMP) {
                return netlink_dump_start(ctnl, skb, nlh,
                                          ctnetlink_exp_dump_table,
-                                         ctnetlink_exp_done);
+                                         ctnetlink_exp_done, 0);
        }
 
        err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
index d29c22254f6b82b62095ca7b723bf5a6b6d99277..10851ee55d188e87b69b60a0e4f825e26da4c4dd 100644 (file)
@@ -1677,13 +1677,10 @@ static int netlink_dump(struct sock *sk)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
        struct netlink_callback *cb;
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
        struct nlmsghdr *nlh;
        int len, err = -ENOBUFS;
-
-       skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL);
-       if (!skb)
-               goto errout;
+       int alloc_size;
 
        mutex_lock(nlk->cb_mutex);
 
@@ -1693,6 +1690,12 @@ static int netlink_dump(struct sock *sk)
                goto errout_skb;
        }
 
+       alloc_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE);
+
+       skb = sock_rmalloc(sk, alloc_size, 0, GFP_KERNEL);
+       if (!skb)
+               goto errout;
+
        len = cb->dump(skb, cb);
 
        if (len > 0) {
@@ -1735,7 +1738,8 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
                       const struct nlmsghdr *nlh,
                       int (*dump)(struct sk_buff *skb,
                                   struct netlink_callback *),
-                      int (*done)(struct netlink_callback *))
+                      int (*done)(struct netlink_callback *),
+                      u16 min_dump_alloc)
 {
        struct netlink_callback *cb;
        struct sock *sk;
@@ -1749,6 +1753,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        cb->dump = dump;
        cb->done = done;
        cb->nlh = nlh;
+       cb->min_dump_alloc = min_dump_alloc;
        atomic_inc(&skb->users);
        cb->skb = skb;
 
index 1781d99145e2d2594fc961e1a2fc9307aad957a5..482fa571b4eecb9b89bc67ac523f0ff6c08ef0f5 100644 (file)
@@ -525,7 +525,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
                genl_unlock();
                err = netlink_dump_start(net->genl_sock, skb, nlh,
-                                        ops->dumpit, ops->done);
+                                        ops->dumpit, ops->done, 0);
                genl_lock();
                return err;
        }
index 438accb7a5a8ada36dea9e769fcd3fce69c50aaf..d61f6761777de54b547c5634853a0a3d7630765e 100644 (file)
@@ -289,15 +289,16 @@ out:
 
 int __init phonet_netlink_register(void)
 {
-       int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL);
+       int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit,
+                                 NULL, NULL);
        if (err)
                return err;
 
        /* Further __rtnl_register() cannot fail */
-       __rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL);
-       __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
-       __rtnl_register(PF_PHONET, RTM_NEWROUTE, route_doit, NULL);
-       __rtnl_register(PF_PHONET, RTM_DELROUTE, route_doit, NULL);
-       __rtnl_register(PF_PHONET, RTM_GETROUTE, NULL, route_dumpit);
+       __rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL, NULL);
+       __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit, NULL);
+       __rtnl_register(PF_PHONET, RTM_NEWROUTE, route_doit, NULL, NULL);
+       __rtnl_register(PF_PHONET, RTM_DELROUTE, route_doit, NULL, NULL);
+       __rtnl_register(PF_PHONET, RTM_GETROUTE, NULL, route_dumpit, NULL);
        return 0;
 }
index a606025814a1a99650d0793c4f3db468b829aaca..2f64262ab5d23d63826cc9afc67816b0dfcfe059 100644 (file)
@@ -1115,9 +1115,10 @@ nlmsg_failure:
 
 static int __init tc_action_init(void)
 {
-       rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL);
-       rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL);
-       rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action);
+       rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action,
+                     NULL);
 
        return 0;
 }
index bb2c523f81587adb116a0f5dc659807d27eda855..9563887f219f64f55e8262ecd8483270c00b1980 100644 (file)
@@ -610,10 +610,10 @@ EXPORT_SYMBOL(tcf_exts_dump_stats);
 
 static int __init tc_filter_init(void)
 {
-       rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL);
-       rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL);
+       rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, NULL);
        rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter,
-                                                tc_dump_tfilter);
+                     tc_dump_tfilter, NULL);
 
        return 0;
 }
index 6b8627661c98e7a778623a6ae1605fefdd895d49..8182aefafb028f39ceda64e1e93b52b87448cf61 100644 (file)
@@ -1792,12 +1792,12 @@ static int __init pktsched_init(void)
        register_qdisc(&pfifo_head_drop_qdisc_ops);
        register_qdisc(&mq_qdisc_ops);
 
-       rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);
-       rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);
-       rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc);
-       rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL);
-       rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL);
-       rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass);
+       rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc, NULL);
+       rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL, NULL);
+       rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass, NULL);
 
        return 0;
 }
index 05f82e62943bcdaf4e472d62c321d1a48b68e044..9bbe858518f859f4bae99aebb6f51e4b6d1c5d9c 100644 (file)
@@ -2326,7 +2326,8 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                if (link->dump == NULL)
                        return -EINVAL;
 
-               return netlink_dump_start(net->xfrm.nlsk, skb, nlh, link->dump, link->done);
+               return netlink_dump_start(net->xfrm.nlsk, skb, nlh,
+                                         link->dump, link->done, 0);
        }
 
        err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,