Commit 86878f14 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

tools: ynl: user space helpers



Add "fixed" part of the user space Netlink Spec-based library.
This will get linked with the protocol implementations to form
a full API.

Acked-by: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent a99bfdf6
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -78,3 +78,82 @@ to see other examples.
The code generation itself is performed by ``tools/net/ynl/ynl-gen-c.py``
but it takes a few arguments so calling it directly for each file
quickly becomes tedious.

YNL lib
=======

``tools/net/ynl/lib/`` contains an implementation of a C library
(based on libmnl) which integrates with code generated by
``tools/net/ynl/ynl-gen-c.py`` to create easy to use netlink wrappers.

YNL basics
----------

The YNL library consists of two parts - the generic code (functions
prefix by ``ynl_``) and per-family auto-generated code (prefixed
with the name of the family).

To create a YNL socket call ynl_sock_create() passing the family
struct (family structs are exported by the auto-generated code).
ynl_sock_destroy() closes the socket.

YNL requests
------------

Steps for issuing YNL requests are best explained on an example.
All the functions and types in this example come from the auto-generated
code (for the netdev family in this case):

.. code-block:: c

   // 0. Request and response pointers
   struct netdev_dev_get_req *req;
   struct netdev_dev_get_rsp *d;

   // 1. Allocate a request
   req = netdev_dev_get_req_alloc();
   // 2. Set request parameters (as needed)
   netdev_dev_get_req_set_ifindex(req, ifindex);

   // 3. Issues the request
   d = netdev_dev_get(ys, req);
   // 4. Free the request arguments
   netdev_dev_get_req_free(req);
   // 5. Error check (the return value from step 3)
   if (!d) {
	// 6. Print the YNL-generated error
	fprintf(stderr, "YNL: %s\n", ys->err.msg);
        return -1;
   }

   // ... do stuff with the response @d

   // 7. Free response
   netdev_dev_get_rsp_free(d);

YNL dumps
---------

Performing dumps follows similar pattern as requests.
Dumps return a list of objects terminated by a special marker,
or NULL on error. Use ``ynl_dump_foreach()`` to iterate over
the result.

YNL notifications
-----------------

YNL lib supports using the same socket for notifications and
requests. In case notifications arrive during processing of a request
they are queued internally and can be retrieved at a later time.

To subscribed to notifications use ``ynl_subscribe()``.
The notifications have to be read out from the socket,
``ynl_socket_get_fd()`` returns the underlying socket fd which can
be plugged into appropriate asynchronous IO API like ``poll``,
or ``select``.

Notifications can be retrieved using ``ynl_ntf_dequeue()`` and have
to be freed using ``ynl_ntf_free()``. Since we don't know the notification
type upfront the notifications are returned as ``struct ynl_ntf_base_type *``
and user is expected to cast them to the appropriate full type based
on the ``cmd`` member.

tools/net/ynl/Makefile

0 → 100644
+19 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0

SUBDIRS = lib generated samples

all: $(SUBDIRS)

$(SUBDIRS):
	@if [ -f "$@/Makefile" ] ; then \
		$(MAKE) -C $@ ; \
	fi

clean hardclean:
	@for dir in $(SUBDIRS) ; do \
		if [ -f "$$dir/Makefile" ] ; then \
			$(MAKE) -C $$dir $@; \
		fi \
	done

.PHONY: clean all $(SUBDIRS)
+45 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0

CC=gcc
CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \
	-I../lib/
ifeq ("$(DEBUG)","1")
  CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan
endif

TOOL:=../ynl-gen-c.py

GENS:=
SRCS=$(patsubst %,%-user.c,${GENS})
HDRS=$(patsubst %,%-user.h,${GENS})
OBJS=$(patsubst %,%-user.o,${GENS})

all: protos.a $(HDRS) $(SRCS) $(KHDRS) $(KSRCS) $(UAPI) regen

protos.a: $(OBJS)
	@echo -e "\tAR $@"
	@ar rcs $@ $(OBJS)

%-user.h: ../../../../Documentation/netlink/specs/%.yaml $(TOOL)
	@echo -e "\tGEN $@"
	@$(TOOL) --mode user --header --spec $< > $@

%-user.c: ../../../../Documentation/netlink/specs/%.yaml $(TOOL)
	@echo -e "\tGEN $@"
	@$(TOOL) --mode user --source --spec $< > $@

%-user.o: %-user.c %-user.h
	@echo -e "\tCC $@"
	@$(COMPILE.c) -c -o $@ $<

clean:
	rm -f *.o

hardclean: clean
	rm -f *.c *.h *.a

regen:
	@../ynl-regen.sh

.PHONY: all clean hardclean regen
.DEFAULT_GOAL: all
+28 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0

CC=gcc
CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow
ifeq ("$(DEBUG)","1")
  CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan
endif

SRCS=$(wildcard *.c)
OBJS=$(patsubst %.c,%.o,${SRCS})

include $(wildcard *.d)

all: ynl.a

ynl.a: $(OBJS)
	ar rcs $@ $(OBJS)
clean:
	rm -f *.o *.d *~

hardclean: clean
	rm -f *.a

%.o: %.c
	$(COMPILE.c) -MMD -c -o $@ $<

.PHONY: all clean
.DEFAULT_GOAL=all
+901 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading