Skip to content

Commit b02d229

Browse files
kuba-mooPaolo Abeni
authored andcommitted
tools: ynltool: create skeleton for the C command
Based on past discussions it seems like integration of YNL into iproute2 is unlikely. YNL itself is not great as a C library, since it has no backward compat (we routinely change types). Most of the operations can be performed with the generic Python CLI directly. There is, however, a handful of operations where summarization of kernel output is very useful (mostly related to stats: page-pool, qstat). Create a command (inspired by bpftool, I think it stood the test of time reasonably well) to be able to plug the subcommands into. Link: https://lore.kernel.org/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> Link: https://patch.msgid.link/[email protected] Acked-by: Stanislav Fomichev <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent 8da7bea commit b02d229

File tree

7 files changed

+720
-1
lines changed

7 files changed

+720
-1
lines changed

tools/net/ynl/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ endif
1212
libdir ?= $(prefix)/$(libdir_relative)
1313
includedir ?= $(prefix)/include
1414

15-
SUBDIRS = lib generated samples
15+
SUBDIRS = lib generated samples ynltool
1616

1717
all: $(SUBDIRS) libynl.a
1818

19+
ynltool: | lib generated libynl.a
1920
samples: | lib generated
2021
libynl.a: | lib generated
2122
@echo -e "\tAR $@"

tools/net/ynl/ynltool/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ynltool

tools/net/ynl/ynltool/Makefile

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
3+
include ../Makefile.deps
4+
5+
INSTALL ?= install
6+
prefix ?= /usr
7+
8+
CC := gcc
9+
CFLAGS := -Wall -Wextra -Werror -O2
10+
ifeq ("$(DEBUG)","1")
11+
CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan
12+
endif
13+
CFLAGS += -I../lib
14+
15+
SRC_VERSION := \
16+
$(shell make --no-print-directory -sC ../../../.. kernelversion || \
17+
echo "unknown")
18+
19+
CFLAGS += -DSRC_VERSION='"$(SRC_VERSION)"'
20+
21+
SRCS := $(wildcard *.c)
22+
OBJS := $(patsubst %.c,$(OUTPUT)%.o,$(SRCS))
23+
24+
YNLTOOL := $(OUTPUT)ynltool
25+
26+
include $(wildcard *.d)
27+
28+
all: $(YNLTOOL)
29+
30+
Q = @
31+
32+
$(YNLTOOL): $(OBJS)
33+
$(Q)echo -e "\tLINK $@"
34+
$(Q)$(CC) $(CFLAGS) -o $@ $(OBJS)
35+
36+
%.o: %.c main.h json_writer.h
37+
$(Q)echo -e "\tCC $@"
38+
$(Q)$(COMPILE.c) -MMD -c -o $@ $<
39+
40+
clean:
41+
rm -f *.o *.d *~
42+
43+
distclean: clean
44+
rm -f $(YNLTOOL)
45+
46+
bindir ?= /usr/bin
47+
48+
install: $(YNLTOOL)
49+
install -m 0755 $(YNLTOOL) $(DESTDIR)$(bindir)/$(YNLTOOL)
50+
51+
.PHONY: all clean distclean
52+
.DEFAULT_GOAL=all
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2+
/*
3+
* Simple streaming JSON writer
4+
*
5+
* This takes care of the annoying bits of JSON syntax like the commas
6+
* after elements
7+
*
8+
* Authors: Stephen Hemminger <[email protected]>
9+
*/
10+
11+
#include <stdio.h>
12+
#include <stdbool.h>
13+
#include <stdarg.h>
14+
#include <assert.h>
15+
#include <malloc.h>
16+
#include <inttypes.h>
17+
#include <stdint.h>
18+
19+
#include "json_writer.h"
20+
21+
struct json_writer {
22+
FILE *out;
23+
unsigned depth;
24+
bool pretty;
25+
char sep;
26+
};
27+
28+
static void jsonw_indent(json_writer_t *self)
29+
{
30+
unsigned i;
31+
for (i = 0; i < self->depth; ++i)
32+
fputs(" ", self->out);
33+
}
34+
35+
static void jsonw_eol(json_writer_t *self)
36+
{
37+
if (!self->pretty)
38+
return;
39+
40+
putc('\n', self->out);
41+
jsonw_indent(self);
42+
}
43+
44+
static void jsonw_eor(json_writer_t *self)
45+
{
46+
if (self->sep != '\0')
47+
putc(self->sep, self->out);
48+
self->sep = ',';
49+
}
50+
51+
static void jsonw_puts(json_writer_t *self, const char *str)
52+
{
53+
putc('"', self->out);
54+
for (; *str; ++str)
55+
switch (*str) {
56+
case '\t':
57+
fputs("\\t", self->out);
58+
break;
59+
case '\n':
60+
fputs("\\n", self->out);
61+
break;
62+
case '\r':
63+
fputs("\\r", self->out);
64+
break;
65+
case '\f':
66+
fputs("\\f", self->out);
67+
break;
68+
case '\b':
69+
fputs("\\b", self->out);
70+
break;
71+
case '\\':
72+
fputs("\\\\", self->out);
73+
break;
74+
case '"':
75+
fputs("\\\"", self->out);
76+
break;
77+
default:
78+
putc(*str, self->out);
79+
}
80+
putc('"', self->out);
81+
}
82+
83+
json_writer_t *jsonw_new(FILE *f)
84+
{
85+
json_writer_t *self = malloc(sizeof(*self));
86+
if (self) {
87+
self->out = f;
88+
self->depth = 0;
89+
self->pretty = false;
90+
self->sep = '\0';
91+
}
92+
return self;
93+
}
94+
95+
void jsonw_destroy(json_writer_t **self_p)
96+
{
97+
json_writer_t *self = *self_p;
98+
99+
assert(self->depth == 0);
100+
fputs("\n", self->out);
101+
fflush(self->out);
102+
free(self);
103+
*self_p = NULL;
104+
}
105+
106+
void jsonw_pretty(json_writer_t *self, bool on)
107+
{
108+
self->pretty = on;
109+
}
110+
111+
void jsonw_reset(json_writer_t *self)
112+
{
113+
assert(self->depth == 0);
114+
self->sep = '\0';
115+
}
116+
117+
static void jsonw_begin(json_writer_t *self, int c)
118+
{
119+
jsonw_eor(self);
120+
putc(c, self->out);
121+
++self->depth;
122+
self->sep = '\0';
123+
}
124+
125+
static void jsonw_end(json_writer_t *self, int c)
126+
{
127+
assert(self->depth > 0);
128+
129+
--self->depth;
130+
if (self->sep != '\0')
131+
jsonw_eol(self);
132+
putc(c, self->out);
133+
self->sep = ',';
134+
}
135+
136+
void jsonw_name(json_writer_t *self, const char *name)
137+
{
138+
jsonw_eor(self);
139+
jsonw_eol(self);
140+
self->sep = '\0';
141+
jsonw_puts(self, name);
142+
putc(':', self->out);
143+
if (self->pretty)
144+
putc(' ', self->out);
145+
}
146+
147+
void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap)
148+
{
149+
jsonw_eor(self);
150+
putc('"', self->out);
151+
vfprintf(self->out, fmt, ap);
152+
putc('"', self->out);
153+
}
154+
155+
void jsonw_printf(json_writer_t *self, const char *fmt, ...)
156+
{
157+
va_list ap;
158+
159+
va_start(ap, fmt);
160+
jsonw_eor(self);
161+
vfprintf(self->out, fmt, ap);
162+
va_end(ap);
163+
}
164+
165+
void jsonw_start_object(json_writer_t *self)
166+
{
167+
jsonw_begin(self, '{');
168+
}
169+
170+
void jsonw_end_object(json_writer_t *self)
171+
{
172+
jsonw_end(self, '}');
173+
}
174+
175+
void jsonw_start_array(json_writer_t *self)
176+
{
177+
jsonw_begin(self, '[');
178+
}
179+
180+
void jsonw_end_array(json_writer_t *self)
181+
{
182+
jsonw_end(self, ']');
183+
}
184+
185+
void jsonw_string(json_writer_t *self, const char *value)
186+
{
187+
jsonw_eor(self);
188+
jsonw_puts(self, value);
189+
}
190+
191+
void jsonw_bool(json_writer_t *self, bool val)
192+
{
193+
jsonw_printf(self, "%s", val ? "true" : "false");
194+
}
195+
196+
void jsonw_null(json_writer_t *self)
197+
{
198+
jsonw_printf(self, "null");
199+
}
200+
201+
void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num)
202+
{
203+
jsonw_printf(self, fmt, num);
204+
}
205+
206+
void jsonw_float(json_writer_t *self, double num)
207+
{
208+
jsonw_printf(self, "%g", num);
209+
}
210+
211+
void jsonw_hu(json_writer_t *self, unsigned short num)
212+
{
213+
jsonw_printf(self, "%hu", num);
214+
}
215+
216+
void jsonw_uint(json_writer_t *self, uint64_t num)
217+
{
218+
jsonw_printf(self, "%"PRIu64, num);
219+
}
220+
221+
void jsonw_lluint(json_writer_t *self, unsigned long long int num)
222+
{
223+
jsonw_printf(self, "%llu", num);
224+
}
225+
226+
void jsonw_int(json_writer_t *self, int64_t num)
227+
{
228+
jsonw_printf(self, "%"PRId64, num);
229+
}
230+
231+
void jsonw_string_field(json_writer_t *self, const char *prop, const char *val)
232+
{
233+
jsonw_name(self, prop);
234+
jsonw_string(self, val);
235+
}
236+
237+
void jsonw_bool_field(json_writer_t *self, const char *prop, bool val)
238+
{
239+
jsonw_name(self, prop);
240+
jsonw_bool(self, val);
241+
}
242+
243+
void jsonw_float_field(json_writer_t *self, const char *prop, double val)
244+
{
245+
jsonw_name(self, prop);
246+
jsonw_float(self, val);
247+
}
248+
249+
void jsonw_float_field_fmt(json_writer_t *self,
250+
const char *prop,
251+
const char *fmt,
252+
double val)
253+
{
254+
jsonw_name(self, prop);
255+
jsonw_float_fmt(self, fmt, val);
256+
}
257+
258+
void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num)
259+
{
260+
jsonw_name(self, prop);
261+
jsonw_uint(self, num);
262+
}
263+
264+
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
265+
{
266+
jsonw_name(self, prop);
267+
jsonw_hu(self, num);
268+
}
269+
270+
void jsonw_lluint_field(json_writer_t *self,
271+
const char *prop,
272+
unsigned long long int num)
273+
{
274+
jsonw_name(self, prop);
275+
jsonw_lluint(self, num);
276+
}
277+
278+
void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num)
279+
{
280+
jsonw_name(self, prop);
281+
jsonw_int(self, num);
282+
}
283+
284+
void jsonw_null_field(json_writer_t *self, const char *prop)
285+
{
286+
jsonw_name(self, prop);
287+
jsonw_null(self);
288+
}

0 commit comments

Comments
 (0)