netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Puneet Sharma <pusharma@akamai.com>
To: stephen@networkplumber.org, dsahern@kernel.org
Cc: netdev@vger.kernel.org
Subject: [PATCH iproute2] tc: add print options to fix json output
Date: Wed, 28 Oct 2020 14:35:54 -0400	[thread overview]
Message-ID: <20201028183554.18078-1-pusharma@akamai.com> (raw)

Currently, json for basic rules output does not produce correct json
syntax. The following fixes were done to correct it for extended
matches for use with "basic" filters.

tc/f_basic.c: replace fprintf with print_uint to support json output.
fixing this prints "handle" tag correctly in json output.

tc/m_ematch.c: replace various fprintf with correct print.
add new "ematch" tag for json output which represents
"tc filter add ... basic match '()'" string. Added print_raw_string
to print raw string instead of key value for json.

lib/json_writer.c: add jsonw_raw_string to print raw text in json.

lib/json_print.c: add print_color_raw_string to print string
depending on context.

example:
$ tc -s -d -j filter show dev <eth_name> ingress
Before:
...
"options": {handle 0x2
  (
    cmp(u8 at 9 layer 1 eq 6)
    OR cmp(u8 at 9 layer 1 eq 17)
  ) AND ipset(test-ipv4 src)

            "actions": [{
...

After:
[{
...
"options": {
    "handle": 1,
    "ematch": "(cmp(u8 at 9 layer 1 eq 6)OR cmp(u8 at 9 layer 1 eq 17)) AND ipset(test-ipv4 src)",
...
]

Signed-off-by: Puneet Sharma <pusharma@akamai.com>
---
 include/json_print.h  |  1 +
 include/json_writer.h |  1 +
 lib/json_print.c      | 17 +++++++++++++++++
 lib/json_writer.c     |  5 +++++
 tc/f_basic.c          |  2 +-
 tc/m_ematch.c         | 26 ++++++++++++++++----------
 6 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/include/json_print.h b/include/json_print.h
index 50e71de4..91af7295 100644
--- a/include/json_print.h
+++ b/include/json_print.h
@@ -67,6 +67,7 @@ _PRINT_FUNC(s64, int64_t)
 _PRINT_FUNC(bool, bool)
 _PRINT_FUNC(null, const char*)
 _PRINT_FUNC(string, const char*)
+_PRINT_FUNC(raw_string, const char*)
 _PRINT_FUNC(uint, unsigned int)
 _PRINT_FUNC(u64, uint64_t)
 _PRINT_FUNC(hhu, unsigned char)
diff --git a/include/json_writer.h b/include/json_writer.h
index b52dc2d0..afb561a6 100644
--- a/include/json_writer.h
+++ b/include/json_writer.h
@@ -31,6 +31,7 @@ void jsonw_name(json_writer_t *self, const char *name);
 /* Add value  */
 __attribute__((format(printf, 2, 3)))
 void jsonw_printf(json_writer_t *self, const char *fmt, ...);
+void jsonw_raw_string(json_writer_t *self, const char *value);
 void jsonw_string(json_writer_t *self, const char *value);
 void jsonw_bool(json_writer_t *self, bool value);
 void jsonw_float(json_writer_t *self, double number);
diff --git a/lib/json_print.c b/lib/json_print.c
index fe0705bf..ff76afba 100644
--- a/lib/json_print.c
+++ b/lib/json_print.c
@@ -186,6 +186,23 @@ int print_color_string(enum output_type type,
 	return ret;
 }
 
+int print_color_raw_string(enum output_type type,
+			enum color_attr color,
+			const char *key,
+			const char *fmt,
+			const char *value)
+{
+	int ret = 0;
+
+	if (_IS_JSON_CONTEXT(type))
+		jsonw_raw_string(_jw, fmt);
+	else if (_IS_FP_CONTEXT(type)) {
+		ret = color_fprintf(stdout, color, fmt, value);
+ 	}
+
+	return ret;
+}
+
 /*
  * value's type is bool. When using this function in FP context you can't pass
  * a value to it, you will need to use "is_json_context()" to have different
diff --git a/lib/json_writer.c b/lib/json_writer.c
index 88c5eb88..80ab0a20 100644
--- a/lib/json_writer.c
+++ b/lib/json_writer.c
@@ -51,6 +51,11 @@ static void jsonw_eor(json_writer_t *self)
 	self->sep = ',';
 }
 
+void jsonw_raw_string(json_writer_t *self, const char *str)
+{
+	for (; *str; ++str)
+		putc(*str, self->out);
+}
 
 /* Output JSON encoded string */
 /* Handles C escapes, does not do Unicode */
diff --git a/tc/f_basic.c b/tc/f_basic.c
index 7b19cea6..444d4297 100644
--- a/tc/f_basic.c
+++ b/tc/f_basic.c
@@ -119,7 +119,7 @@ static int basic_print_opt(struct filter_util *qu, FILE *f,
 	parse_rtattr_nested(tb, TCA_BASIC_MAX, opt);
 
 	if (handle)
-		fprintf(f, "handle 0x%x ", handle);
+		print_uint(PRINT_ANY, "handle", "handle 0x%x ", handle);
 
 	if (tb[TCA_BASIC_CLASSID]) {
 		SPRINT_BUF(b1);
diff --git a/tc/m_ematch.c b/tc/m_ematch.c
index 8840a0dc..eee3819f 100644
--- a/tc/m_ematch.c
+++ b/tc/m_ematch.c
@@ -408,7 +408,7 @@ static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
 		hdr = RTA_DATA(tb[i]);
 
 		if (hdr->flags & TCF_EM_INVERT)
-			fprintf(fd, "NOT ");
+			print_raw_string(PRINT_ANY, NULL, "NOT ", NULL);
 
 		if (hdr->kind == 0) {
 			__u32 ref;
@@ -417,14 +417,15 @@ static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
 				return -1;
 
 			ref = *(__u32 *) data;
-			fprintf(fd, "(\n");
+			print_raw_string(PRINT_ANY, NULL, "(", NULL);
+			print_string(PRINT_FP, NULL, "\n", NULL);
 			for (n = 0; n <= prefix; n++)
-				fprintf(fd, "  ");
+				print_string(PRINT_FP, NULL, "  ", NULL);
 			if (print_ematch_seq(fd, tb, ref + 1, prefix + 1) < 0)
 				return -1;
 			for (n = 0; n < prefix; n++)
-				fprintf(fd, "  ");
-			fprintf(fd, ") ");
+				print_string(PRINT_FP, NULL, "  ", NULL);
+			print_raw_string(PRINT_ANY, NULL, ") ", NULL);
 
 		} else {
 			struct ematch_util *e;
@@ -437,20 +438,21 @@ static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
 				fprintf(fd, "%s(", e->kind);
 				if (e->print_eopt(fd, hdr, data, dlen) < 0)
 					return -1;
-				fprintf(fd, ")\n");
+				print_raw_string(PRINT_ANY, NULL, ")", NULL);
+				print_string(PRINT_FP, NULL, "\n", NULL);
 			}
 			if (hdr->flags & TCF_EM_REL_MASK)
 				for (n = 0; n < prefix; n++)
-					fprintf(fd, "  ");
+					print_string(PRINT_FP, NULL, "  ", NULL);
 		}
 
 		switch (hdr->flags & TCF_EM_REL_MASK) {
 			case TCF_EM_REL_AND:
-				fprintf(fd, "AND ");
+				print_raw_string(PRINT_ANY, NULL, "AND ", NULL);
 				break;
 
 			case TCF_EM_REL_OR:
-				fprintf(fd, "OR ");
+				print_raw_string(PRINT_ANY, NULL, "OR ", NULL);
 				break;
 
 			default:
@@ -477,9 +479,13 @@ static int print_ematch_list(FILE *fd, struct tcf_ematch_tree_hdr *hdr,
 		if (parse_rtattr_nested(tb, hdr->nmatches, rta) < 0)
 			goto errout;
 
-		fprintf(fd, "\n  ");
+		print_string(PRINT_FP, NULL, "\n  ", NULL);
+		print_string(PRINT_JSON, "ematch", NULL, NULL);
+		print_raw_string(PRINT_JSON, NULL, "\"", NULL);
 		if (print_ematch_seq(fd, tb, 1, 1) < 0)
 			goto errout;
+
+		print_raw_string(PRINT_JSON, NULL, "\",", NULL);
 	}
 
 	err = 0;
-- 
2.24.1 (Apple Git-126)


             reply	other threads:[~2020-10-29  0:18 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-28 18:35 Puneet Sharma [this message]
2020-10-29 20:17 ` [PATCH iproute2] tc: add print options to fix json output Stephen Hemminger
     [not found]   ` <2B38A297-343E-4DD0-93E2-87F8B2AC1E26@akamai.com>
2020-10-29 23:16     ` Stephen Hemminger
2020-10-30  0:42       ` Sharma, Puneet
2020-10-30  2:47         ` David Ahern

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201028183554.18078-1-pusharma@akamai.com \
    --to=pusharma@akamai.com \
    --cc=dsahern@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=stephen@networkplumber.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).