diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 69 |
1 files changed, 57 insertions, 12 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2d56cb9b0b94..99d9e953fe39 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); |
@@ -1009,6 +1032,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
1009 | s_idx = cb->args[1]; | 1032 | s_idx = cb->args[1]; |
1010 | 1033 | ||
1011 | rcu_read_lock(); | 1034 | rcu_read_lock(); |
1035 | cb->seq = net->dev_base_seq; | ||
1036 | |||
1012 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 1037 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
1013 | idx = 0; | 1038 | idx = 0; |
1014 | head = &net->dev_index_head[h]; | 1039 | head = &net->dev_index_head[h]; |
@@ -1020,6 +1045,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
1020 | cb->nlh->nlmsg_seq, 0, | 1045 | cb->nlh->nlmsg_seq, 0, |
1021 | NLM_F_MULTI) <= 0) | 1046 | NLM_F_MULTI) <= 0) |
1022 | goto out; | 1047 | goto out; |
1048 | |||
1049 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
1023 | cont: | 1050 | cont: |
1024 | idx++; | 1051 | idx++; |
1025 | } | 1052 | } |
@@ -1046,6 +1073,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
1046 | [IFLA_LINKMODE] = { .type = NLA_U8 }, | 1073 | [IFLA_LINKMODE] = { .type = NLA_U8 }, |
1047 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, | 1074 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, |
1048 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 1075 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
1076 | [IFLA_NET_NS_FD] = { .type = NLA_U32 }, | ||
1049 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, | 1077 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, |
1050 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, | 1078 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, |
1051 | [IFLA_VF_PORTS] = { .type = NLA_NESTED }, | 1079 | [IFLA_VF_PORTS] = { .type = NLA_NESTED }, |
@@ -1094,6 +1122,8 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) | |||
1094 | */ | 1122 | */ |
1095 | if (tb[IFLA_NET_NS_PID]) | 1123 | if (tb[IFLA_NET_NS_PID]) |
1096 | net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); | 1124 | net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); |
1125 | else if (tb[IFLA_NET_NS_FD]) | ||
1126 | net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD])); | ||
1097 | else | 1127 | else |
1098 | net = get_net(src_net); | 1128 | net = get_net(src_net); |
1099 | return net; | 1129 | return net; |
@@ -1224,7 +1254,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1224 | int send_addr_notify = 0; | 1254 | int send_addr_notify = 0; |
1225 | int err; | 1255 | int err; |
1226 | 1256 | ||
1227 | if (tb[IFLA_NET_NS_PID]) { | 1257 | if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { |
1228 | struct net *net = rtnl_link_get_net(dev_net(dev), tb); | 1258 | struct net *net = rtnl_link_get_net(dev_net(dev), tb); |
1229 | if (IS_ERR(net)) { | 1259 | if (IS_ERR(net)) { |
1230 | err = PTR_ERR(net); | 1260 | err = PTR_ERR(net); |
@@ -1815,6 +1845,11 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
1815 | return err; | 1845 | return err; |
1816 | } | 1846 | } |
1817 | 1847 | ||
1848 | static u16 rtnl_calcit(struct sk_buff *skb) | ||
1849 | { | ||
1850 | return min_ifinfo_dump_size; | ||
1851 | } | ||
1852 | |||
1818 | static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | 1853 | static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) |
1819 | { | 1854 | { |
1820 | int idx; | 1855 | int idx; |
@@ -1844,11 +1879,14 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) | |||
1844 | struct net *net = dev_net(dev); | 1879 | struct net *net = dev_net(dev); |
1845 | struct sk_buff *skb; | 1880 | struct sk_buff *skb; |
1846 | int err = -ENOBUFS; | 1881 | int err = -ENOBUFS; |
1882 | size_t if_info_size; | ||
1847 | 1883 | ||
1848 | skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); | 1884 | skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), GFP_KERNEL); |
1849 | if (skb == NULL) | 1885 | if (skb == NULL) |
1850 | goto errout; | 1886 | goto errout; |
1851 | 1887 | ||
1888 | min_ifinfo_dump_size = max_t(u16, if_info_size, min_ifinfo_dump_size); | ||
1889 | |||
1852 | err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0); | 1890 | err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0); |
1853 | if (err < 0) { | 1891 | if (err < 0) { |
1854 | /* -EMSGSIZE implies BUG in if_nlmsg_size() */ | 1892 | /* -EMSGSIZE implies BUG in if_nlmsg_size() */ |
@@ -1899,14 +1937,20 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1899 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { | 1937 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |
1900 | struct sock *rtnl; | 1938 | struct sock *rtnl; |
1901 | rtnl_dumpit_func dumpit; | 1939 | rtnl_dumpit_func dumpit; |
1940 | rtnl_calcit_func calcit; | ||
1941 | u16 min_dump_alloc = 0; | ||
1902 | 1942 | ||
1903 | dumpit = rtnl_get_dumpit(family, type); | 1943 | dumpit = rtnl_get_dumpit(family, type); |
1904 | if (dumpit == NULL) | 1944 | if (dumpit == NULL) |
1905 | return -EOPNOTSUPP; | 1945 | return -EOPNOTSUPP; |
1946 | calcit = rtnl_get_calcit(family, type); | ||
1947 | if (calcit) | ||
1948 | min_dump_alloc = calcit(skb); | ||
1906 | 1949 | ||
1907 | __rtnl_unlock(); | 1950 | __rtnl_unlock(); |
1908 | rtnl = net->rtnl; | 1951 | rtnl = net->rtnl; |
1909 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); | 1952 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, |
1953 | NULL, min_dump_alloc); | ||
1910 | rtnl_lock(); | 1954 | rtnl_lock(); |
1911 | return err; | 1955 | return err; |
1912 | } | 1956 | } |
@@ -2016,12 +2060,13 @@ void __init rtnetlink_init(void) | |||
2016 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); | 2060 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); |
2017 | register_netdevice_notifier(&rtnetlink_dev_notifier); | 2061 | register_netdevice_notifier(&rtnetlink_dev_notifier); |
2018 | 2062 | ||
2019 | rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo); | 2063 | rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, |
2020 | rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL); | 2064 | rtnl_dump_ifinfo, rtnl_calcit); |
2021 | rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL); | 2065 | rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL, NULL); |
2022 | rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL); | 2066 | rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL, NULL); |
2067 | rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL, NULL); | ||
2023 | 2068 | ||
2024 | rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all); | 2069 | rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all, NULL); |
2025 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all); | 2070 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, NULL); |
2026 | } | 2071 | } |
2027 | 2072 | ||