Message ID | 168564136118.7284.18138054610456895287.stgit@anambiarhost.jf.intel.com (mailing list archive) |
---|---|
State | RFC |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | Introduce napi queues support | expand |
On Thu, Jun 01, 2023 at 10:42:41AM -0700, Amritha Nambiar wrote: > Add support in ynl/netdev.yaml for napi related information. The > netdev structure tracks all the napi instances and napi fields. > The napi instances and associated queue[s] can be retrieved this way. > > Refactored netdev-genl to support exposing napi<->queue[s] mapping > that is retained in a netdev. Hi Amritha, This feels like it should be two patches to me. Though it is not something I feel strongly about. > Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com> ... > +static int > +netdev_nl_dev_napi_prepare_fill(struct net_device *netdev, > + struct sk_buff **pskb, u32 portid, u32 seq, > + int flags, u32 cmd, enum netdev_nl_type type) > +{ > + struct nlmsghdr *nlh; > + struct sk_buff *skb = *pskb; > + bool last = false; > + int index = 0; > + void *hdr; > + int err; > + nit: please use reverse xmas tree - longest line to shortest - for local variable declarations in (new) Networking code. ...
On Fri, 2 Jun 2023 17:47:17 +0200 Simon Horman wrote: > This feels like it should be two patches to me. > Though it is not something I feel strongly about. +1 I'd put the YAML and what's generated from it in one patch, and the hand-written code in another.
On Thu, 01 Jun 2023 10:42:41 -0700 Amritha Nambiar wrote: > Add support in ynl/netdev.yaml for napi related information. The > netdev structure tracks all the napi instances and napi fields. > The napi instances and associated queue[s] can be retrieved this way. > > Refactored netdev-genl to support exposing napi<->queue[s] mapping > that is retained in a netdev. > > Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com> > --- > Documentation/netlink/specs/netdev.yaml | 39 +++++ > include/uapi/linux/netdev.h | 4 + > net/core/netdev-genl.c | 239 ++++++++++++++++++++++++++----- > tools/include/uapi/linux/netdev.h | 4 + > 4 files changed, 247 insertions(+), 39 deletions(-) > > diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml > index b99e7ffef7a1..8d0edb529563 100644 > --- a/Documentation/netlink/specs/netdev.yaml > +++ b/Documentation/netlink/specs/netdev.yaml > @@ -62,6 +62,44 @@ attribute-sets: > type: u64 > enum: xdp-act > enum-as-flags: true > + - > + name: napi-info > + doc: napi information such as napi-id, napi queues etc. > + type: nest > + multi-attr: true Let's make a new attr space for the napi info command. We don't reuse much of the attributes, and as the commands grow stuffing all attrs into one space makes finding stuff harder. > + nested-attributes: dev-napi-info And what's inside this nest should also be a separate attr space. > + - > + name: napi-id > + doc: napi id > + type: u32 > + - > + name: rx-queues > + doc: list of rx queues associated with a napi > + type: u16 Make it u32, at the uAPI level we're tried to the width of fields, and u16 ends up being the same size as u32 "on the wire" due to padding. > + multi-attr: true > + - > + name: tx-queues > + doc: list of tx queues associated with a napi > + type: u16 > + multi-attr: true > + - > + name: dev-napi-info > + subset-of: dev Yeah, this shouldn't be a subset just a full-on separate attr space. The handshake family may be a good example to look at, it's the biggest so far written with the new rules in mind. > + attributes: > + - > + name: napi-id > + doc: napi id > + type: u32 > + - > + name: rx-queues > + doc: list rx of queues associated with a napi > + type: u16 > + multi-attr: true > + - > + name: tx-queues > + doc: list tx of queues associated with a napi > + type: u16 > + multi-attr: true > > operations: > list: > @@ -77,6 +115,7 @@ operations: > attributes: > - ifindex > - xdp-features > + - napi-info Aaah, separate command, please. Let's not stuff all the information into a single command like we did for rtnl. > dump: > reply: *dev-all > -
On 6/2/2023 8:47 AM, Simon Horman wrote: > On Thu, Jun 01, 2023 at 10:42:41AM -0700, Amritha Nambiar wrote: >> Add support in ynl/netdev.yaml for napi related information. The >> netdev structure tracks all the napi instances and napi fields. >> The napi instances and associated queue[s] can be retrieved this way. >> >> Refactored netdev-genl to support exposing napi<->queue[s] mapping >> that is retained in a netdev. > > Hi Amritha, > > This feels like it should be two patches to me. > Though it is not something I feel strongly about. > Thanks for pointing that out, I'll split this patch into two. >> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com> > > ... > >> +static int >> +netdev_nl_dev_napi_prepare_fill(struct net_device *netdev, >> + struct sk_buff **pskb, u32 portid, u32 seq, >> + int flags, u32 cmd, enum netdev_nl_type type) >> +{ >> + struct nlmsghdr *nlh; >> + struct sk_buff *skb = *pskb; >> + bool last = false; >> + int index = 0; >> + void *hdr; >> + int err; >> + > > nit: please use reverse xmas tree - longest line to shortest - for > local variable declarations in (new) Networking code. > > ... Will fix in next version.
On 6/2/2023 11:08 PM, Jakub Kicinski wrote: > On Fri, 2 Jun 2023 17:47:17 +0200 Simon Horman wrote: >> This feels like it should be two patches to me. >> Though it is not something I feel strongly about. > > +1 I'd put the YAML and what's generated from it in one patch, > and the hand-written code in another. Will fix in the next version.
On 6/2/2023 11:17 PM, Jakub Kicinski wrote: > On Thu, 01 Jun 2023 10:42:41 -0700 Amritha Nambiar wrote: >> Add support in ynl/netdev.yaml for napi related information. The >> netdev structure tracks all the napi instances and napi fields. >> The napi instances and associated queue[s] can be retrieved this way. >> >> Refactored netdev-genl to support exposing napi<->queue[s] mapping >> that is retained in a netdev. >> >> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com> >> --- >> Documentation/netlink/specs/netdev.yaml | 39 +++++ >> include/uapi/linux/netdev.h | 4 + >> net/core/netdev-genl.c | 239 ++++++++++++++++++++++++++----- >> tools/include/uapi/linux/netdev.h | 4 + >> 4 files changed, 247 insertions(+), 39 deletions(-) >> >> diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml >> index b99e7ffef7a1..8d0edb529563 100644 >> --- a/Documentation/netlink/specs/netdev.yaml >> +++ b/Documentation/netlink/specs/netdev.yaml >> @@ -62,6 +62,44 @@ attribute-sets: >> type: u64 >> enum: xdp-act >> enum-as-flags: true >> + - >> + name: napi-info >> + doc: napi information such as napi-id, napi queues etc. >> + type: nest >> + multi-attr: true > > Let's make a new attr space for the napi info command. > We don't reuse much of the attributes, and as the commands > grow stuffing all attrs into one space makes finding stuff > harder. > Agree. I should not have overloaded the 'dev' command to begin with. >> + nested-attributes: dev-napi-info > > And what's inside this nest should also be a separate attr space. > So, I think we could have two new commands for napi data. Would this be acceptable, a 'napi-queue-get' command for napi-queue specific information (set of TX and RX queues, IRQ number etc.), and another 'napi-info-get' for other information, such as PID for the napi thread, CPU etc. Example: $ ./cli.py --spec netdev.yaml --do napi-queue-get --json='{"ifindex": 12}' [{'napi-info': [{'napi-id': 600, 'rx-queues': [7], 'tx-queues': [7], 'irq': 298}, {'napi-id': 599, 'rx-queues': [6], 'tx-queues': [6], 'irq': 297}, {'napi-id': 598, 'rx-queues': [5], 'tx-queues': [5], 'irq': 296}, {'napi-id': 597, 'rx-queues': [4], 'tx-queues': [4], 'irq': 295}, {'napi-id': 596, 'rx-queues': [3], 'tx-queues': [3], 'irq': 294}, {'napi-id': 595, 'rx-queues': [2], 'tx-queues': [2], 'irq': 293}, {'napi-id': 594, 'rx-queues': [1], 'tx-queues': [1], 'irq': 292}, {'napi-id': 593, 'rx-queues': [0], 'tx-queues': [0], 'irq': 291}]}] $ ./cli.py --spec netdev.yaml --do napi-info-get --json='{"ifindex": 12}' [{'napi-info': [{'napi-id': 600, 'pid': 68114}, {'napi-id': 599, 'pid': 68113}, {'napi-id': 598, 'pid': 68112}, {'napi-id': 597, 'pid': 68111}, {'napi-id': 596, 'pid': 68110}, {'napi-id': 595, 'pid': 68109}, {'napi-id': 594, 'pid': 68108}, {'napi-id': 593, 'pid': 68107}]}] > >> + - >> + name: napi-id >> + doc: napi id >> + type: u32 >> + - >> + name: rx-queues >> + doc: list of rx queues associated with a napi >> + type: u16 > > Make it u32, at the uAPI level we're tried to the width of fields, and > u16 ends up being the same size as u32 "on the wire" due to padding. > Makes sense. Will fix. >> + multi-attr: true >> + - >> + name: tx-queues >> + doc: list of tx queues associated with a napi >> + type: u16 >> + multi-attr: true > > >> + - >> + name: dev-napi-info >> + subset-of: dev > > Yeah, this shouldn't be a subset just a full-on separate attr space. > The handshake family may be a good example to look at, it's the biggest > so far written with the new rules in mind. > Okay. >> + attributes: >> + - >> + name: napi-id >> + doc: napi id >> + type: u32 >> + - >> + name: rx-queues >> + doc: list rx of queues associated with a napi >> + type: u16 >> + multi-attr: true >> + - >> + name: tx-queues >> + doc: list tx of queues associated with a napi >> + type: u16 >> + multi-attr: true >> >> operations: >> list: >> @@ -77,6 +115,7 @@ operations: >> attributes: >> - ifindex >> - xdp-features >> + - napi-info > > Aaah, separate command, please. Let's not stuff all the information > into a single command like we did for rtnl. > Okay. >> dump: >> reply: *dev-all >> -
On Wed, 12 Jul 2023 13:10:45 -0700 Nambiar, Amritha wrote: > So, I think we could have two new commands for napi data. Would this be > acceptable, a 'napi-queue-get' command for napi-queue specific > information (set of TX and RX queues, IRQ number etc.), and another > 'napi-info-get' for other information, such as PID for the napi thread, > CPU etc. > > Example: > $ ./cli.py --spec netdev.yaml --do napi-queue-get --json='{"ifindex": > 12}' > > [{'napi-info': [{'napi-id': 600, 'rx-queues': [7], 'tx-queues': [7], > 'irq': 298}, I think the commands make sense. You should echo back the ifindex, tho, it threw me off initially that there's only on attribute ('napi-info') in the reply, in which case the nest would have been pointless..
diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index b99e7ffef7a1..8d0edb529563 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -62,6 +62,44 @@ attribute-sets: type: u64 enum: xdp-act enum-as-flags: true + - + name: napi-info + doc: napi information such as napi-id, napi queues etc. + type: nest + multi-attr: true + nested-attributes: dev-napi-info + - + name: napi-id + doc: napi id + type: u32 + - + name: rx-queues + doc: list of rx queues associated with a napi + type: u16 + multi-attr: true + - + name: tx-queues + doc: list of tx queues associated with a napi + type: u16 + multi-attr: true + - + name: dev-napi-info + subset-of: dev + attributes: + - + name: napi-id + doc: napi id + type: u32 + - + name: rx-queues + doc: list rx of queues associated with a napi + type: u16 + multi-attr: true + - + name: tx-queues + doc: list tx of queues associated with a napi + type: u16 + multi-attr: true operations: list: @@ -77,6 +115,7 @@ operations: attributes: - ifindex - xdp-features + - napi-info dump: reply: *dev-all - diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index 639524b59930..16538fb1406a 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -41,6 +41,10 @@ enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, NETDEV_A_DEV_XDP_FEATURES, + NETDEV_A_DEV_NAPI_INFO, + NETDEV_A_DEV_NAPI_ID, + NETDEV_A_DEV_RX_QUEUES, + NETDEV_A_DEV_TX_QUEUES, __NETDEV_A_DEV_MAX, NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index 8d6a840821c7..fdaa67f53b22 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -11,6 +11,7 @@ struct netdev_nl_dump_ctx { int dev_entry_hash; int dev_entry_idx; + int napi_idx; }; static inline struct netdev_nl_dump_ctx * @@ -21,54 +22,187 @@ netdev_dump_ctx(struct netlink_callback *cb) return (struct netdev_nl_dump_ctx *)cb->ctx; } +enum netdev_nl_type { + NETDEV_NL_DO, + NETDEV_NL_NOTIFY, +}; + +static int netdev_nl_send_func(struct net_device *netdev, struct sk_buff *skb, + u32 portid, enum netdev_nl_type type) +{ + switch (type) { + case NETDEV_NL_DO: + return genlmsg_unicast(dev_net(netdev), skb, portid); + case NETDEV_NL_NOTIFY: + return genlmsg_multicast_netns(&netdev_nl_family, + dev_net(netdev), skb, 0, + NETDEV_NLGRP_MGMT, GFP_KERNEL); + default: + return -EINVAL; + } +} + static int -netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp, - u32 portid, u32 seq, int flags, u32 cmd) +netdev_nl_dev_napi_fill_one(struct sk_buff *msg, struct napi_struct *napi) { - void *hdr; + struct nlattr *napi_info; + struct napi_queue *q, *n; - hdr = genlmsg_put(rsp, portid, seq, &netdev_nl_family, flags, cmd); - if (!hdr) + napi_info = nla_nest_start(msg, NETDEV_A_DEV_NAPI_INFO); + if (!napi_info) return -EMSGSIZE; + if (nla_put_u32(msg, NETDEV_A_DEV_NAPI_ID, napi->napi_id)) + goto nla_put_failure; + + list_for_each_entry_safe(q, n, &napi->napi_rxq_list, q_list) { + if (nla_put_u16(msg, NETDEV_A_DEV_RX_QUEUES, q->queue_index)) + goto nla_put_failure; + } + + list_for_each_entry_safe(q, n, &napi->napi_txq_list, q_list) { + if (nla_put_u16(msg, NETDEV_A_DEV_TX_QUEUES, q->queue_index)) + goto nla_put_failure; + } + nla_nest_end(msg, napi_info); + return 0; +nla_put_failure: + nla_nest_cancel(msg, napi_info); + return -EMSGSIZE; +} + +static int +netdev_nl_dev_napi_fill(struct net_device *netdev, struct sk_buff *msg, int *start) +{ + struct napi_struct *napi, *n; + int i = 0; + + list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) { + if (i < *start) { + i++; + continue; + } + if (netdev_nl_dev_napi_fill_one(msg, napi)) + return -EMSGSIZE; + *start = ++i; + } + return 0; +} + +static int +netdev_nl_dev_napi_prepare_fill(struct net_device *netdev, + struct sk_buff **pskb, u32 portid, u32 seq, + int flags, u32 cmd, enum netdev_nl_type type) +{ + struct nlmsghdr *nlh; + struct sk_buff *skb = *pskb; + bool last = false; + int index = 0; + void *hdr; + int err; + + while (!last) { + int tmp_index = index; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + hdr = genlmsg_put(skb, portid, seq, &netdev_nl_family, + flags | NLM_F_MULTI, cmd); + if (!hdr) { + err = -EMSGSIZE; + goto nla_put_failure; + } + err = netdev_nl_dev_napi_fill(netdev, skb, &index); + if (!err) + last = true; + else if (err != -EMSGSIZE || tmp_index == index) + goto nla_put_failure; + + genlmsg_end(skb, hdr); + err = netdev_nl_send_func(netdev, skb, portid, type); + if (err) + return err; + } + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + nlh = nlmsg_put(skb, portid, seq, NLMSG_DONE, 0, flags | NLM_F_MULTI); + if (!nlh) { + err = -EMSGSIZE; + goto nla_put_failure; + } + + return netdev_nl_send_func(netdev, skb, portid, type); + +nla_put_failure: + nlmsg_free(skb); + return err; +} + +static int +netdev_nl_dev_info_fill(struct net_device *netdev, struct sk_buff *rsp) +{ if (nla_put_u32(rsp, NETDEV_A_DEV_IFINDEX, netdev->ifindex) || nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_FEATURES, - netdev->xdp_features, NETDEV_A_DEV_PAD)) { - genlmsg_cancel(rsp, hdr); - return -EINVAL; + netdev->xdp_features, NETDEV_A_DEV_PAD)) + return -EMSGSIZE; + return 0; +} + +static int +netdev_nl_dev_fill(struct net_device *netdev, u32 portid, u32 seq, int flags, + u32 cmd, enum netdev_nl_type type) +{ + struct sk_buff *skb; + void *hdr; + int err; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + hdr = genlmsg_put(skb, portid, seq, &netdev_nl_family, flags, cmd); + if (!hdr) { + err = -EMSGSIZE; + goto err_free_msg; + } + err = netdev_nl_dev_info_fill(netdev, skb); + if (err) { + genlmsg_cancel(skb, hdr); + goto err_free_msg; } - genlmsg_end(rsp, hdr); + genlmsg_end(skb, hdr); - return 0; + err = netdev_nl_send_func(netdev, skb, portid, type); + if (err) + return err; + + return netdev_nl_dev_napi_prepare_fill(netdev, &skb, portid, seq, flags, + cmd, type); + +err_free_msg: + nlmsg_free(skb); + return err; } static void netdev_genl_dev_notify(struct net_device *netdev, int cmd) { - struct sk_buff *ntf; - if (!genl_has_listeners(&netdev_nl_family, dev_net(netdev), NETDEV_NLGRP_MGMT)) return; - ntf = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!ntf) - return; - - if (netdev_nl_dev_fill(netdev, ntf, 0, 0, 0, cmd)) { - nlmsg_free(ntf); - return; - } + netdev_nl_dev_fill(netdev, 0, 0, 0, cmd, NETDEV_NL_NOTIFY); - genlmsg_multicast_netns(&netdev_nl_family, dev_net(netdev), ntf, - 0, NETDEV_NLGRP_MGMT, GFP_KERNEL); } int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info) { struct net_device *netdev; - struct sk_buff *rsp; u32 ifindex; int err; @@ -77,29 +211,53 @@ int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info) ifindex = nla_get_u32(info->attrs[NETDEV_A_DEV_IFINDEX]); - rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!rsp) - return -ENOMEM; - rtnl_lock(); netdev = __dev_get_by_index(genl_info_net(info), ifindex); if (netdev) - err = netdev_nl_dev_fill(netdev, rsp, info->snd_portid, - info->snd_seq, 0, info->genlhdr->cmd); + err = netdev_nl_dev_fill(netdev, info->snd_portid, + info->snd_seq, 0, info->genlhdr->cmd, + NETDEV_NL_DO); else err = -ENODEV; rtnl_unlock(); - if (err) - goto err_free_msg; + return err; - return genlmsg_reply(rsp, info); + return 0; +} + +static int +netdev_nl_dev_dump_entry(struct net_device *netdev, struct sk_buff *rsp, + struct netlink_callback *cb, int *start) +{ + int index = *start; + int tmp_index = index; + void *hdr; + int err; + + hdr = genlmsg_put(rsp, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &netdev_nl_family, NLM_F_MULTI, NETDEV_CMD_DEV_GET); + if (!hdr) + return -EMSGSIZE; + + if (netdev_nl_dev_info_fill(netdev, rsp)) + goto nla_put_failure; + + err = netdev_nl_dev_napi_fill(netdev, rsp, &index); + if (err) { + if (err != -EMSGSIZE || tmp_index == index) + goto nla_put_failure; + } + *start = index; + genlmsg_end(rsp, hdr); -err_free_msg: - nlmsg_free(rsp); return err; + +nla_put_failure: + genlmsg_cancel(rsp, hdr); + return -EINVAL; } int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) @@ -107,12 +265,13 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb); struct net *net = sock_net(skb->sk); struct net_device *netdev; - int idx = 0, s_idx; + int idx = 0, s_idx, n_idx; int h, s_h; int err; s_h = ctx->dev_entry_hash; s_idx = ctx->dev_entry_idx; + n_idx = ctx->napi_idx; rtnl_lock(); @@ -124,10 +283,10 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) hlist_for_each_entry(netdev, head, index_hlist) { if (idx < s_idx) goto cont; - err = netdev_nl_dev_fill(netdev, skb, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, 0, - NETDEV_CMD_DEV_GET); + err = netdev_nl_dev_dump_entry(netdev, skb, cb, &n_idx); + if (err == -EMSGSIZE) + goto out; + n_idx = 0; if (err < 0) break; cont: @@ -135,6 +294,7 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } } +out: rtnl_unlock(); if (err != -EMSGSIZE) @@ -142,6 +302,7 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) ctx->dev_entry_idx = idx; ctx->dev_entry_hash = h; + ctx->napi_idx = n_idx; cb->seq = net->dev_base_seq; return skb->len; diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index 639524b59930..16538fb1406a 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -41,6 +41,10 @@ enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, NETDEV_A_DEV_XDP_FEATURES, + NETDEV_A_DEV_NAPI_INFO, + NETDEV_A_DEV_NAPI_ID, + NETDEV_A_DEV_RX_QUEUES, + NETDEV_A_DEV_TX_QUEUES, __NETDEV_A_DEV_MAX, NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1)
Add support in ynl/netdev.yaml for napi related information. The netdev structure tracks all the napi instances and napi fields. The napi instances and associated queue[s] can be retrieved this way. Refactored netdev-genl to support exposing napi<->queue[s] mapping that is retained in a netdev. Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com> --- Documentation/netlink/specs/netdev.yaml | 39 +++++ include/uapi/linux/netdev.h | 4 + net/core/netdev-genl.c | 239 ++++++++++++++++++++++++++----- tools/include/uapi/linux/netdev.h | 4 + 4 files changed, 247 insertions(+), 39 deletions(-)