Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

genetlink: allow dumping command-specific policy

Right now CTRL_CMD_GETPOLICY can only dump the family-wide
policy. Support dumping policy of a specific op.

v3:
- rebase after per-op policy export and handle that
v2:
- make cmd U32, just in case.
v1:
- don't echo op in the output in a naive way, this should
make it cleaner to extend the output format for dumping
policies for all the commands at once in the future.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/r/20201001225933.1373426-11-kuba@kernel.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jakub Kicinski and committed by
David S. Miller
e992a6ed 50a896cf

+37 -5
+1
include/uapi/linux/genetlink.h
··· 65 65 CTRL_ATTR_MCAST_GROUPS, 66 66 CTRL_ATTR_POLICY, 67 67 CTRL_ATTR_OP_POLICY, 68 + CTRL_ATTR_OP, 68 69 __CTRL_ATTR_MAX, 69 70 }; 70 71
+36 -5
net/netlink/genetlink.c
··· 123 123 op->policy = family->policy; 124 124 } 125 125 126 - static int genl_get_cmd_full(u8 cmd, const struct genl_family *family, 126 + static int genl_get_cmd_full(u32 cmd, const struct genl_family *family, 127 127 struct genl_ops *op) 128 128 { 129 129 int i; ··· 152 152 op->policy = family->policy; 153 153 } 154 154 155 - static int genl_get_cmd_small(u8 cmd, const struct genl_family *family, 155 + static int genl_get_cmd_small(u32 cmd, const struct genl_family *family, 156 156 struct genl_ops *op) 157 157 { 158 158 int i; ··· 166 166 return -ENOENT; 167 167 } 168 168 169 - static int genl_get_cmd(u8 cmd, const struct genl_family *family, 169 + static int genl_get_cmd(u32 cmd, const struct genl_family *family, 170 170 struct genl_ops *op) 171 171 { 172 172 if (!genl_get_cmd_full(cmd, family, op)) ··· 1114 1114 struct netlink_policy_dump_state *state; 1115 1115 const struct genl_family *rt; 1116 1116 unsigned int opidx; 1117 + u32 op; 1117 1118 u16 fam_id; 1118 - u8 policies:1; 1119 + u8 policies:1, 1120 + single_op:1; 1119 1121 }; 1120 1122 1121 1123 static const struct nla_policy ctrl_policy_policy[] = { 1122 1124 [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, 1123 1125 [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING, 1124 1126 .len = GENL_NAMSIZ - 1 }, 1127 + [CTRL_ATTR_OP] = { .type = NLA_U32 }, 1125 1128 }; 1126 1129 1127 1130 static int ctrl_dumppolicy_start(struct netlink_callback *cb) ··· 1156 1153 return -ENOENT; 1157 1154 1158 1155 ctx->rt = rt; 1156 + 1157 + if (tb[CTRL_ATTR_OP]) { 1158 + ctx->single_op = true; 1159 + ctx->op = nla_get_u32(tb[CTRL_ATTR_OP]); 1160 + 1161 + err = genl_get_cmd(ctx->op, rt, &op); 1162 + if (err) { 1163 + NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]); 1164 + return err; 1165 + } 1166 + 1167 + if (!op.policy) 1168 + return -ENODATA; 1169 + 1170 + return netlink_policy_dump_add_policy(&ctx->state, op.policy, 1171 + op.maxattr); 1172 + } 1159 1173 1160 1174 for (i = 0; i < genl_get_cmd_cnt(rt); i++) { 1161 1175 genl_get_cmd_by_index(i, rt, &op); ··· 1268 1248 while (ctx->opidx < genl_get_cmd_cnt(ctx->rt)) { 1269 1249 struct genl_ops op; 1270 1250 1271 - genl_get_cmd_by_index(ctx->opidx, ctx->rt, &op); 1251 + if (ctx->single_op) { 1252 + int err; 1253 + 1254 + err = genl_get_cmd(ctx->op, ctx->rt, &op); 1255 + if (WARN_ON(err)) 1256 + return skb->len; 1257 + 1258 + /* break out of the loop after this one */ 1259 + ctx->opidx = genl_get_cmd_cnt(ctx->rt); 1260 + } else { 1261 + genl_get_cmd_by_index(ctx->opidx, ctx->rt, &op); 1262 + } 1272 1263 1273 1264 if (ctrl_dumppolicy_put_op(skb, cb, &op)) 1274 1265 return skb->len;