Commit 506a74db authored by Florian Westphal's avatar Florian Westphal Committed by Alexei Starovoitov

netfilter: nfnetlink hook: dump bpf prog id

This allows userspace ("nft list hooks") to show which bpf program
is attached to which hook.

Without this, user only knows bpf prog is attached at prio
x, y, z at INPUT and FORWARD, but can't tell which program is where.

v4: kdoc fixups (Simon Horman)

Link: https://lore.kernel.org/bpf/ZEELzpNCnYJuZyod@corigine.com/Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Link: https://lore.kernel.org/r/20230421170300.24115-4-fw@strlen.deSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent fd9c663b
...@@ -32,8 +32,12 @@ enum nfnl_hook_attributes { ...@@ -32,8 +32,12 @@ enum nfnl_hook_attributes {
/** /**
* enum nfnl_hook_chain_info_attributes - chain description * enum nfnl_hook_chain_info_attributes - chain description
* *
* NFNLA_HOOK_INFO_DESC: nft chain and table name (enum nft_table_attributes) (NLA_NESTED) * @NFNLA_HOOK_INFO_DESC: nft chain and table name (NLA_NESTED)
* NFNLA_HOOK_INFO_TYPE: chain type (enum nfnl_hook_chaintype) (NLA_U32) * @NFNLA_HOOK_INFO_TYPE: chain type (enum nfnl_hook_chaintype) (NLA_U32)
*
* NFNLA_HOOK_INFO_DESC depends on NFNLA_HOOK_INFO_TYPE value:
* NFNL_HOOK_TYPE_NFTABLES: enum nft_table_attributes
* NFNL_HOOK_TYPE_BPF: enum nfnl_hook_bpf_attributes
*/ */
enum nfnl_hook_chain_info_attributes { enum nfnl_hook_chain_info_attributes {
NFNLA_HOOK_INFO_UNSPEC, NFNLA_HOOK_INFO_UNSPEC,
...@@ -55,10 +59,24 @@ enum nfnl_hook_chain_desc_attributes { ...@@ -55,10 +59,24 @@ enum nfnl_hook_chain_desc_attributes {
/** /**
* enum nfnl_hook_chaintype - chain type * enum nfnl_hook_chaintype - chain type
* *
* @NFNL_HOOK_TYPE_NFTABLES nf_tables base chain * @NFNL_HOOK_TYPE_NFTABLES: nf_tables base chain
* @NFNL_HOOK_TYPE_BPF: bpf program
*/ */
enum nfnl_hook_chaintype { enum nfnl_hook_chaintype {
NFNL_HOOK_TYPE_NFTABLES = 0x1, NFNL_HOOK_TYPE_NFTABLES = 0x1,
NFNL_HOOK_TYPE_BPF,
};
/**
* enum nfnl_hook_bpf_attributes - bpf prog description
*
* @NFNLA_HOOK_BPF_ID: bpf program id (NLA_U32)
*/
enum nfnl_hook_bpf_attributes {
NFNLA_HOOK_BPF_UNSPEC,
NFNLA_HOOK_BPF_ID,
__NFNLA_HOOK_BPF_MAX,
}; };
#define NFNLA_HOOK_BPF_MAX (__NFNLA_HOOK_BPF_MAX - 1)
#endif /* _NFNL_HOOK_H */ #endif /* _NFNL_HOOK_H */
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Author: Florian Westphal <fw@strlen.de> * Author: Florian Westphal <fw@strlen.de>
*/ */
#include <linux/bpf.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -57,35 +58,76 @@ struct nfnl_dump_hook_data { ...@@ -57,35 +58,76 @@ struct nfnl_dump_hook_data {
u8 hook; u8 hook;
}; };
static struct nlattr *nfnl_start_info_type(struct sk_buff *nlskb, enum nfnl_hook_chaintype t)
{
struct nlattr *nest = nla_nest_start(nlskb, NFNLA_HOOK_CHAIN_INFO);
int ret;
if (!nest)
return NULL;
ret = nla_put_be32(nlskb, NFNLA_HOOK_INFO_TYPE, htonl(t));
if (ret == 0)
return nest;
nla_nest_cancel(nlskb, nest);
return NULL;
}
static int nfnl_hook_put_bpf_prog_info(struct sk_buff *nlskb,
const struct nfnl_dump_hook_data *ctx,
unsigned int seq,
const struct bpf_prog *prog)
{
struct nlattr *nest, *nest2;
int ret;
if (!IS_ENABLED(CONFIG_NETFILTER_BPF_LINK))
return 0;
if (WARN_ON_ONCE(!prog))
return 0;
nest = nfnl_start_info_type(nlskb, NFNL_HOOK_TYPE_BPF);
if (!nest)
return -EMSGSIZE;
nest2 = nla_nest_start(nlskb, NFNLA_HOOK_INFO_DESC);
if (!nest2)
goto cancel_nest;
ret = nla_put_be32(nlskb, NFNLA_HOOK_BPF_ID, htonl(prog->aux->id));
if (ret)
goto cancel_nest;
nla_nest_end(nlskb, nest2);
nla_nest_end(nlskb, nest);
return 0;
cancel_nest:
nla_nest_cancel(nlskb, nest);
return -EMSGSIZE;
}
static int nfnl_hook_put_nft_chain_info(struct sk_buff *nlskb, static int nfnl_hook_put_nft_chain_info(struct sk_buff *nlskb,
const struct nfnl_dump_hook_data *ctx, const struct nfnl_dump_hook_data *ctx,
unsigned int seq, unsigned int seq,
const struct nf_hook_ops *ops) struct nft_chain *chain)
{ {
struct net *net = sock_net(nlskb->sk); struct net *net = sock_net(nlskb->sk);
struct nlattr *nest, *nest2; struct nlattr *nest, *nest2;
struct nft_chain *chain;
int ret = 0; int ret = 0;
if (ops->hook_ops_type != NF_HOOK_OP_NF_TABLES)
return 0;
chain = ops->priv;
if (WARN_ON_ONCE(!chain)) if (WARN_ON_ONCE(!chain))
return 0; return 0;
if (!nft_is_active(net, chain)) if (!nft_is_active(net, chain))
return 0; return 0;
nest = nla_nest_start(nlskb, NFNLA_HOOK_CHAIN_INFO); nest = nfnl_start_info_type(nlskb, NFNL_HOOK_TYPE_NFTABLES);
if (!nest) if (!nest)
return -EMSGSIZE; return -EMSGSIZE;
ret = nla_put_be32(nlskb, NFNLA_HOOK_INFO_TYPE,
htonl(NFNL_HOOK_TYPE_NFTABLES));
if (ret)
goto cancel_nest;
nest2 = nla_nest_start(nlskb, NFNLA_HOOK_INFO_DESC); nest2 = nla_nest_start(nlskb, NFNLA_HOOK_INFO_DESC);
if (!nest2) if (!nest2)
goto cancel_nest; goto cancel_nest;
...@@ -171,7 +213,20 @@ static int nfnl_hook_dump_one(struct sk_buff *nlskb, ...@@ -171,7 +213,20 @@ static int nfnl_hook_dump_one(struct sk_buff *nlskb,
if (ret) if (ret)
goto nla_put_failure; goto nla_put_failure;
ret = nfnl_hook_put_nft_chain_info(nlskb, ctx, seq, ops); switch (ops->hook_ops_type) {
case NF_HOOK_OP_NF_TABLES:
ret = nfnl_hook_put_nft_chain_info(nlskb, ctx, seq, ops->priv);
break;
case NF_HOOK_OP_BPF:
ret = nfnl_hook_put_bpf_prog_info(nlskb, ctx, seq, ops->priv);
break;
case NF_HOOK_OP_UNDEFINED:
break;
default:
WARN_ON_ONCE(1);
break;
}
if (ret) if (ret)
goto nla_put_failure; goto nla_put_failure;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment