|
8 | 8 | #include <net/xdp.h>
|
9 | 9 | #include <net/xdp_sock.h>
|
10 | 10 | #include <net/netdev_rx_queue.h>
|
| 11 | +#include <net/busy_poll.h> |
11 | 12 |
|
12 | 13 | #include "netdev-genl-gen.h"
|
| 14 | +#include "dev.h" |
13 | 15 |
|
14 | 16 | struct netdev_nl_dump_ctx {
|
15 | 17 | unsigned long ifindex;
|
16 | 18 | unsigned int rxq_idx;
|
17 | 19 | unsigned int txq_idx;
|
| 20 | + unsigned int napi_id; |
18 | 21 | };
|
19 | 22 |
|
20 | 23 | static struct netdev_nl_dump_ctx *netdev_dump_ctx(struct netlink_callback *cb)
|
@@ -155,14 +158,128 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
155 | 158 | return skb->len;
|
156 | 159 | }
|
157 | 160 |
|
| 161 | +static int |
| 162 | +netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi, |
| 163 | + const struct genl_info *info) |
| 164 | +{ |
| 165 | + void *hdr; |
| 166 | + |
| 167 | + if (WARN_ON_ONCE(!napi->dev)) |
| 168 | + return -EINVAL; |
| 169 | + if (!(napi->dev->flags & IFF_UP)) |
| 170 | + return 0; |
| 171 | + |
| 172 | + hdr = genlmsg_iput(rsp, info); |
| 173 | + if (!hdr) |
| 174 | + return -EMSGSIZE; |
| 175 | + |
| 176 | + if (napi->napi_id >= MIN_NAPI_ID && |
| 177 | + nla_put_u32(rsp, NETDEV_A_NAPI_ID, napi->napi_id)) |
| 178 | + goto nla_put_failure; |
| 179 | + |
| 180 | + if (nla_put_u32(rsp, NETDEV_A_NAPI_IFINDEX, napi->dev->ifindex)) |
| 181 | + goto nla_put_failure; |
| 182 | + |
| 183 | + genlmsg_end(rsp, hdr); |
| 184 | + return 0; |
| 185 | + |
| 186 | +nla_put_failure: |
| 187 | + genlmsg_cancel(rsp, hdr); |
| 188 | + return -EMSGSIZE; |
| 189 | +} |
| 190 | + |
158 | 191 | int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info)
|
159 | 192 | {
|
160 |
| - return -EOPNOTSUPP; |
| 193 | + struct napi_struct *napi; |
| 194 | + struct sk_buff *rsp; |
| 195 | + u32 napi_id; |
| 196 | + int err; |
| 197 | + |
| 198 | + if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_NAPI_ID)) |
| 199 | + return -EINVAL; |
| 200 | + |
| 201 | + napi_id = nla_get_u32(info->attrs[NETDEV_A_NAPI_ID]); |
| 202 | + |
| 203 | + rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| 204 | + if (!rsp) |
| 205 | + return -ENOMEM; |
| 206 | + |
| 207 | + rtnl_lock(); |
| 208 | + |
| 209 | + napi = napi_by_id(napi_id); |
| 210 | + if (napi) |
| 211 | + err = netdev_nl_napi_fill_one(rsp, napi, info); |
| 212 | + else |
| 213 | + err = -EINVAL; |
| 214 | + |
| 215 | + rtnl_unlock(); |
| 216 | + |
| 217 | + if (err) |
| 218 | + goto err_free_msg; |
| 219 | + |
| 220 | + return genlmsg_reply(rsp, info); |
| 221 | + |
| 222 | +err_free_msg: |
| 223 | + nlmsg_free(rsp); |
| 224 | + return err; |
| 225 | +} |
| 226 | + |
| 227 | +static int |
| 228 | +netdev_nl_napi_dump_one(struct net_device *netdev, struct sk_buff *rsp, |
| 229 | + const struct genl_info *info, |
| 230 | + struct netdev_nl_dump_ctx *ctx) |
| 231 | +{ |
| 232 | + struct napi_struct *napi; |
| 233 | + int err = 0; |
| 234 | + |
| 235 | + if (!(netdev->flags & IFF_UP)) |
| 236 | + return err; |
| 237 | + |
| 238 | + list_for_each_entry(napi, &netdev->napi_list, dev_list) { |
| 239 | + if (ctx->napi_id && napi->napi_id >= ctx->napi_id) |
| 240 | + continue; |
| 241 | + |
| 242 | + err = netdev_nl_napi_fill_one(rsp, napi, info); |
| 243 | + if (err) |
| 244 | + return err; |
| 245 | + ctx->napi_id = napi->napi_id; |
| 246 | + } |
| 247 | + return err; |
161 | 248 | }
|
162 | 249 |
|
163 | 250 | int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
164 | 251 | {
|
165 |
| - return -EOPNOTSUPP; |
| 252 | + struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb); |
| 253 | + const struct genl_info *info = genl_info_dump(cb); |
| 254 | + struct net *net = sock_net(skb->sk); |
| 255 | + struct net_device *netdev; |
| 256 | + u32 ifindex = 0; |
| 257 | + int err = 0; |
| 258 | + |
| 259 | + if (info->attrs[NETDEV_A_NAPI_IFINDEX]) |
| 260 | + ifindex = nla_get_u32(info->attrs[NETDEV_A_NAPI_IFINDEX]); |
| 261 | + |
| 262 | + rtnl_lock(); |
| 263 | + if (ifindex) { |
| 264 | + netdev = __dev_get_by_index(net, ifindex); |
| 265 | + if (netdev) |
| 266 | + err = netdev_nl_napi_dump_one(netdev, skb, info, ctx); |
| 267 | + else |
| 268 | + err = -ENODEV; |
| 269 | + } else { |
| 270 | + for_each_netdev_dump(net, netdev, ctx->ifindex) { |
| 271 | + err = netdev_nl_napi_dump_one(netdev, skb, info, ctx); |
| 272 | + if (err < 0) |
| 273 | + break; |
| 274 | + ctx->napi_id = 0; |
| 275 | + } |
| 276 | + } |
| 277 | + rtnl_unlock(); |
| 278 | + |
| 279 | + if (err != -EMSGSIZE) |
| 280 | + return err; |
| 281 | + |
| 282 | + return skb->len; |
166 | 283 | }
|
167 | 284 |
|
168 | 285 | static int
|
|
0 commit comments