Skip to content

Commit

Permalink
Merge branch 'genetlink-per-op-policy-export'
Browse files Browse the repository at this point in the history
Johannes Berg says:

====================
genetlink per-op policy export

Here's a respin, now including Jakub's patch last so that it will
do the right thing from the start.

The first patch remains the same, of course; the others have mostly
some rebasing going on, except for the actual export patch (patch 4)
which is adjusted per Jakub's review comments about exporting the
policy only if it's actually used for do/dump.

To see that, the dump for "nlctrl" (i.e. the generic netlink control)
is instructive, because the ops are this:

        {
                .cmd            = CTRL_CMD_GETFAMILY,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .policy         = ctrl_policy_family,
                .maxattr        = ARRAY_SIZE(ctrl_policy_family) - 1,
                .doit           = ctrl_getfamily,
                .dumpit         = ctrl_dumpfamily,
        },
        {
                .cmd            = CTRL_CMD_GETPOLICY,
                .policy         = ctrl_policy_policy,
                .maxattr        = ARRAY_SIZE(ctrl_policy_policy) - 1,
                .start          = ctrl_dumppolicy_start,
                .dumpit         = ctrl_dumppolicy,
                .done           = ctrl_dumppolicy_done,
        },

So we exercise both "don't have doit" and "GENL_DONT_VALIDATE_DUMP"
parts, and get (with the current genl patch):

$ genl ctrl policy name nlctrl
	ID: 0x10  op 3 policies: do=0
	ID: 0x10  op 10 policies: dump=1
	ID: 0x10  policy[0]:attr[1]: type=U16 range:[0,65535]
	ID: 0x10  policy[0]:attr[2]: type=NUL_STRING max len:15
	ID: 0x10  policy[1]:attr[1]: type=U16 range:[0,65535]
	ID: 0x10  policy[1]:attr[2]: type=NUL_STRING max len:15
	ID: 0x10  policy[1]:attr[10]: type=U32 range:[0,4294967295]
====================

Reviewed-by: Jakub Kicinski <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Oct 3, 2020
2 parents 678cdd4 + e992a6e commit 186e26e
Show file tree
Hide file tree
Showing 4 changed files with 247 additions and 40 deletions.
9 changes: 6 additions & 3 deletions include/net/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -1937,9 +1937,12 @@ void nla_get_range_signed(const struct nla_policy *pt,

struct netlink_policy_dump_state;

int netlink_policy_dump_start(const struct nla_policy *policy,
unsigned int maxtype,
struct netlink_policy_dump_state **state);
int netlink_policy_dump_add_policy(struct netlink_policy_dump_state **pstate,
const struct nla_policy *policy,
unsigned int maxtype);
int netlink_policy_dump_get_policy_idx(struct netlink_policy_dump_state *state,
const struct nla_policy *policy,
unsigned int maxtype);
bool netlink_policy_dump_loop(struct netlink_policy_dump_state *state);
int netlink_policy_dump_write(struct sk_buff *skb,
struct netlink_policy_dump_state *state);
Expand Down
11 changes: 11 additions & 0 deletions include/uapi/linux/genetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ enum {
CTRL_ATTR_OPS,
CTRL_ATTR_MCAST_GROUPS,
CTRL_ATTR_POLICY,
CTRL_ATTR_OP_POLICY,
CTRL_ATTR_OP,
__CTRL_ATTR_MAX,
};

Expand All @@ -85,6 +87,15 @@ enum {
__CTRL_ATTR_MCAST_GRP_MAX,
};

enum {
CTRL_ATTR_POLICY_UNSPEC,
CTRL_ATTR_POLICY_DO,
CTRL_ATTR_POLICY_DUMP,

__CTRL_ATTR_POLICY_DUMP_MAX,
CTRL_ATTR_POLICY_DUMP_MAX = __CTRL_ATTR_POLICY_DUMP_MAX - 1
};

#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)


Expand Down
161 changes: 144 additions & 17 deletions net/netlink/genetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ static void genl_op_from_full(const struct genl_family *family,
op->policy = family->policy;
}

static int genl_get_cmd_full(u8 cmd, const struct genl_family *family,
static int genl_get_cmd_full(u32 cmd, const struct genl_family *family,
struct genl_ops *op)
{
int i;
Expand Down Expand Up @@ -152,7 +152,7 @@ static void genl_op_from_small(const struct genl_family *family,
op->policy = family->policy;
}

static int genl_get_cmd_small(u8 cmd, const struct genl_family *family,
static int genl_get_cmd_small(u32 cmd, const struct genl_family *family,
struct genl_ops *op)
{
int i;
Expand All @@ -166,7 +166,7 @@ static int genl_get_cmd_small(u8 cmd, const struct genl_family *family,
return -ENOENT;
}

static int genl_get_cmd(u8 cmd, const struct genl_family *family,
static int genl_get_cmd(u32 cmd, const struct genl_family *family,
struct genl_ops *op)
{
if (!genl_get_cmd_full(cmd, family, op))
Expand Down Expand Up @@ -1112,13 +1112,19 @@ static int genl_ctrl_event(int event, const struct genl_family *family,

struct ctrl_dump_policy_ctx {
struct netlink_policy_dump_state *state;
const struct genl_family *rt;
unsigned int opidx;
u32 op;
u16 fam_id;
u8 policies:1,
single_op:1;
};

static const struct nla_policy ctrl_policy_policy[] = {
[CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
[CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
.len = GENL_NAMSIZ - 1 },
[CTRL_ATTR_OP] = { .type = NLA_U32 },
};

static int ctrl_dumppolicy_start(struct netlink_callback *cb)
Expand All @@ -1127,6 +1133,8 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
struct nlattr **tb = info->attrs;
const struct genl_family *rt;
struct genl_ops op;
int err, i;

BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));

Expand All @@ -1147,29 +1155,149 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
if (!rt)
return -ENOENT;

if (!rt->policy)
ctx->rt = rt;

if (tb[CTRL_ATTR_OP]) {
ctx->single_op = true;
ctx->op = nla_get_u32(tb[CTRL_ATTR_OP]);

err = genl_get_cmd(ctx->op, rt, &op);
if (err) {
NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]);
return err;
}

if (!op.policy)
return -ENODATA;

return netlink_policy_dump_add_policy(&ctx->state, op.policy,
op.maxattr);
}

for (i = 0; i < genl_get_cmd_cnt(rt); i++) {
genl_get_cmd_by_index(i, rt, &op);

if (op.policy) {
err = netlink_policy_dump_add_policy(&ctx->state,
op.policy,
op.maxattr);
if (err)
return err;
}
}

if (!ctx->state)
return -ENODATA;
return 0;
}

return netlink_policy_dump_start(rt->policy, rt->maxattr, &ctx->state);
static void *ctrl_dumppolicy_prep(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
void *hdr;

hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, &genl_ctrl,
NLM_F_MULTI, CTRL_CMD_GETPOLICY);
if (!hdr)
return NULL;

if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
return NULL;

return hdr;
}

static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
struct netlink_callback *cb,
struct genl_ops *op)
{
struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
struct nlattr *nest_pol, *nest_op;
void *hdr;
int idx;

/* skip if we have nothing to show */
if (!op->policy)
return 0;
if (!op->doit &&
(!op->dumpit || op->validate & GENL_DONT_VALIDATE_DUMP))
return 0;

hdr = ctrl_dumppolicy_prep(skb, cb);
if (!hdr)
return -ENOBUFS;

nest_pol = nla_nest_start(skb, CTRL_ATTR_OP_POLICY);
if (!nest_pol)
goto err;

nest_op = nla_nest_start(skb, op->cmd);
if (!nest_op)
goto err;

/* for now both do/dump are always the same */
idx = netlink_policy_dump_get_policy_idx(ctx->state,
op->policy,
op->maxattr);

if (op->doit && nla_put_u32(skb, CTRL_ATTR_POLICY_DO, idx))
goto err;

if (op->dumpit && !(op->validate & GENL_DONT_VALIDATE_DUMP) &&
nla_put_u32(skb, CTRL_ATTR_POLICY_DUMP, idx))
goto err;

nla_nest_end(skb, nest_op);
nla_nest_end(skb, nest_pol);
genlmsg_end(skb, hdr);

return 0;
err:
genlmsg_cancel(skb, hdr);
return -ENOBUFS;
}

static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
{
struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
void *hdr;

if (!ctx->policies) {
while (ctx->opidx < genl_get_cmd_cnt(ctx->rt)) {
struct genl_ops op;

if (ctx->single_op) {
int err;

err = genl_get_cmd(ctx->op, ctx->rt, &op);
if (WARN_ON(err))
return skb->len;

/* break out of the loop after this one */
ctx->opidx = genl_get_cmd_cnt(ctx->rt);
} else {
genl_get_cmd_by_index(ctx->opidx, ctx->rt, &op);
}

if (ctrl_dumppolicy_put_op(skb, cb, &op))
return skb->len;

ctx->opidx++;
}

/* completed with the per-op policy index list */
ctx->policies = true;
}

while (netlink_policy_dump_loop(ctx->state)) {
void *hdr;
struct nlattr *nest;

hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, &genl_ctrl,
NLM_F_MULTI, CTRL_CMD_GETPOLICY);
hdr = ctrl_dumppolicy_prep(skb, cb);
if (!hdr)
goto nla_put_failure;

if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
goto nla_put_failure;

nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
if (!nest)
goto nla_put_failure;
Expand All @@ -1180,14 +1308,13 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
nla_nest_end(skb, nest);

genlmsg_end(skb, hdr);
continue;

nla_put_failure:
genlmsg_cancel(skb, hdr);
break;
}

return skb->len;

nla_put_failure:
genlmsg_cancel(skb, hdr);
return skb->len;
}

static int ctrl_dumppolicy_done(struct netlink_callback *cb)
Expand Down
Loading

0 comments on commit 186e26e

Please sign in to comment.