diff mbox series

[2/2] genl: ctrl: support dumping netlink policy

Message ID 20200819102903.21740-2-johannes@sipsolutions.net
State Changes Requested
Delegated to: David Ahern
Headers show
Series [1/2] libnetlink: add rtattr_for_each_nested() iteration macro | expand

Commit Message

Johannes Berg Aug. 19, 2020, 10:29 a.m. UTC
Support dumping the netlink policy of a given generic netlink
family, the policy (with any sub-policies if appropriate) is
exported by the kernel in a general fashion.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 genl/ctrl.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 85 insertions(+), 6 deletions(-)

Comments

David Ahern Aug. 24, 2020, 1:45 a.m. UTC | #1
On 8/19/20 4:29 AM, Johannes Berg wrote:
> @@ -100,6 +102,30 @@ static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
>  
>  }
>  
> +static const char *get_nla_type_str(unsigned int attr)
> +{
> +	switch (attr) {
> +#define C(x) case NL_ATTR_TYPE_ ## x: return #x
> +	C(U8);
> +	C(U16);
> +	C(U32);
> +	C(U64);
> +	C(STRING);
> +	C(FLAG);
> +	C(NESTED);
> +	C(NESTED_ARRAY);
> +	C(NUL_STRING);
> +	C(BINARY);
> +	C(S8);
> +	C(S16);
> +	C(S32);
> +	C(S64);
> +	C(BITFIELD32);
> +	default:
> +		return "unknown";
> +	}
> +}
> +

This should go in libnetlink since it generic NLA type strings.

>  /*
>   * The controller sends one nlmsg per family
>  */
Johannes Berg Aug. 24, 2020, 7:54 a.m. UTC | #2
On Sun, 2020-08-23 at 19:45 -0600, David Ahern wrote:
> On 8/19/20 4:29 AM, Johannes Berg wrote:
> > @@ -100,6 +102,30 @@ static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
> >  
> >  }
> >  
> > +static const char *get_nla_type_str(unsigned int attr)
> > +{
> > +	switch (attr) {
> > +#define C(x) case NL_ATTR_TYPE_ ## x: return #x
> > +	C(U8);
> > +	C(U16);
> > +	C(U32);
> > +	C(U64);
> > +	C(STRING);
> > +	C(FLAG);
> > +	C(NESTED);
> > +	C(NESTED_ARRAY);
> > +	C(NUL_STRING);
> > +	C(BINARY);
> > +	C(S8);
> > +	C(S16);
> > +	C(S32);
> > +	C(S64);
> > +	C(BITFIELD32);
> > +	default:
> > +		return "unknown";
> > +	}
> > +}
> > +
> 
> This should go in libnetlink since it generic NLA type strings.

Arguably, pretty much all of the code here should go into libnetlink
then, since the kernel facility was expressly written in a way that
would allow dumping out arbitrary (not just generic netlink) policies,
just needs wiring up in the appropriate netlink family (or perhaps some
additional "policy netlink" family?)

I can make that change, but I sort of assumed it'd be nicer to do that
when someone else actually picked it up.

johannes
David Ahern Aug. 24, 2020, 4:54 p.m. UTC | #3
On 8/24/20 1:54 AM, Johannes Berg wrote:
> Arguably, pretty much all of the code here should go into libnetlink
> then, since the kernel facility was expressly written in a way that
> would allow dumping out arbitrary (not just generic netlink) policies,
> just needs wiring up in the appropriate netlink family (or perhaps some
> additional "policy netlink" family?)

good point.

> 
> I can make that change, but I sort of assumed it'd be nicer to do that
> when someone else actually picked it up.

I think it would be better to put this into libnetlink from the start.
diff mbox series

Patch

diff --git a/genl/ctrl.c b/genl/ctrl.c
index 0fb464b01cfb..7767fffe63ea 100644
--- a/genl/ctrl.c
+++ b/genl/ctrl.c
@@ -28,13 +28,15 @@ 
 static int usage(void)
 {
 	fprintf(stderr,"Usage: ctrl <CMD>\n" \
-		       "CMD   := get <PARMS> | list | monitor\n" \
+		       "CMD   := get <PARMS> | list | monitor | policy <PARMS>\n" \
 		       "PARMS := name <name> | id <id>\n" \
 		       "Examples:\n" \
 		       "\tctrl ls\n" \
 		       "\tctrl monitor\n" \
 		       "\tctrl get name foobar\n" \
-		       "\tctrl get id 0xF\n");
+		       "\tctrl get id 0xF\n"
+		       "\tctrl policy name foobar\n"
+		       "\tctrl policy id 0xF\n");
 	return -1;
 }
 
@@ -100,6 +102,30 @@  static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
 
 }
 
+static const char *get_nla_type_str(unsigned int attr)
+{
+	switch (attr) {
+#define C(x) case NL_ATTR_TYPE_ ## x: return #x
+	C(U8);
+	C(U16);
+	C(U32);
+	C(U64);
+	C(STRING);
+	C(FLAG);
+	C(NESTED);
+	C(NESTED_ARRAY);
+	C(NUL_STRING);
+	C(BINARY);
+	C(S8);
+	C(S16);
+	C(S32);
+	C(S64);
+	C(BITFIELD32);
+	default:
+		return "unknown";
+	}
+}
+
 /*
  * The controller sends one nlmsg per family
 */
@@ -123,7 +149,8 @@  static int print_ctrl(struct rtnl_ctrl_data *ctrl,
 	    ghdr->cmd != CTRL_CMD_DELFAMILY &&
 	    ghdr->cmd != CTRL_CMD_NEWFAMILY &&
 	    ghdr->cmd != CTRL_CMD_NEWMCAST_GRP &&
-	    ghdr->cmd != CTRL_CMD_DELMCAST_GRP) {
+	    ghdr->cmd != CTRL_CMD_DELMCAST_GRP &&
+	    ghdr->cmd != CTRL_CMD_GETPOLICY) {
 		fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
 		return 0;
 	}
@@ -136,7 +163,7 @@  static int print_ctrl(struct rtnl_ctrl_data *ctrl,
 	}
 
 	attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
-	parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+	parse_rtattr_flags(tb, CTRL_ATTR_MAX, attrs, len, NLA_F_NESTED);
 
 	if (tb[CTRL_ATTR_FAMILY_NAME]) {
 		char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
@@ -159,6 +186,52 @@  static int print_ctrl(struct rtnl_ctrl_data *ctrl,
 		__u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]);
 		fprintf(fp, " max attribs: %d ",*ma);
 	}
+	if (tb[CTRL_ATTR_POLICY]) {
+		const struct rtattr *pos;
+
+		rtattr_for_each_nested(pos, tb[CTRL_ATTR_POLICY]) {
+			const struct rtattr *attr;
+
+			fprintf(fp, " policy[%u]:", pos->rta_type & ~NLA_F_NESTED);
+
+			rtattr_for_each_nested(attr, pos) {
+				struct rtattr *tp[NL_POLICY_TYPE_ATTR_MAX + 1];
+
+				parse_rtattr_nested(tp, ARRAY_SIZE(tp) - 1, attr);
+
+				if (tp[NL_POLICY_TYPE_ATTR_TYPE])
+					fprintf(fp, "attr[%u]: type=%s",
+						attr->rta_type & ~NLA_F_NESTED,
+						get_nla_type_str(rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_TYPE])));
+
+				if (tp[NL_POLICY_TYPE_ATTR_POLICY_IDX])
+					fprintf(fp, " policy:%u",
+						rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_POLICY_IDX]));
+
+				if (tp[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE])
+					fprintf(fp, " maxattr:%u",
+						rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE]));
+
+				if (tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_S] && tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_S])
+					fprintf(fp, " range:[%lld,%lld]",
+						(signed long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_S]),
+						(signed long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_S]));
+
+				if (tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_U] && tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_U])
+					fprintf(fp, " range:[%llu,%llu]",
+						(unsigned long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_U]),
+						(unsigned long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_U]));
+
+				if (tp[NL_POLICY_TYPE_ATTR_MIN_LENGTH])
+					fprintf(fp, " min len:%u",
+						rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_MIN_LENGTH]));
+
+				if (tp[NL_POLICY_TYPE_ATTR_MAX_LENGTH])
+					fprintf(fp, " max len:%u",
+						rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_MAX_LENGTH]));
+			}
+		}
+	}
 	/* end of family definitions .. */
 	fprintf(fp,"\n");
 	if (tb[CTRL_ATTR_OPS]) {
@@ -235,7 +308,9 @@  static int ctrl_list(int cmd, int argc, char **argv)
 		exit(1);
 	}
 
-	if (cmd == CTRL_CMD_GETFAMILY) {
+	if (cmd == CTRL_CMD_GETFAMILY || cmd == CTRL_CMD_GETPOLICY) {
+		req.g.cmd = cmd;
+
 		if (argc != 2) {
 			fprintf(stderr, "Wrong number of params\n");
 			return -1;
@@ -260,7 +335,9 @@  static int ctrl_list(int cmd, int argc, char **argv)
 			fprintf(stderr, "Wrong params\n");
 			goto ctrl_done;
 		}
+	}
 
+	if (cmd == CTRL_CMD_GETFAMILY) {
 		if (rtnl_talk(&rth, nlh, &answer) < 0) {
 			fprintf(stderr, "Error talking to the kernel\n");
 			goto ctrl_done;
@@ -273,7 +350,7 @@  static int ctrl_list(int cmd, int argc, char **argv)
 
 	}
 
-	if (cmd == CTRL_CMD_UNSPEC) {
+	if (cmd == CTRL_CMD_UNSPEC || cmd == CTRL_CMD_GETPOLICY) {
 		nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
 		nlh->nlmsg_seq = rth.dump = ++rth.seq;
 
@@ -324,6 +401,8 @@  static int parse_ctrl(struct genl_util *a, int argc, char **argv)
 	    matches(*argv, "show") == 0 ||
 	    matches(*argv, "lst") == 0)
 		return ctrl_list(CTRL_CMD_UNSPEC, argc-1, argv+1);
+	if (matches(*argv, "policy") == 0)
+		return ctrl_list(CTRL_CMD_GETPOLICY, argc-1, argv+1);
 	if (matches(*argv, "help") == 0)
 		return usage();