mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Adjust parsing and rendering appropriately to make sub-messages work.
Rendering is pretty trivial, as the submsg -> netlink conversion looks
like rendering a nest in which only one attr was set. Only trick
is that we use the enum value of the sub-message rather than the nest
as the type, and effectively skip one layer of nesting. A real double
nested struct would look like this:
  [SELECTOR]
  [SUBMSG]
    [NEST]
      [MSG1-ATTR]
A submsg "is" the nest so by skipping I mean:
  [SELECTOR]
  [SUBMSG]
    [MSG1-ATTR]
There is no extra validation in YNL if caller has set the selector
matching the submsg type (e.g. link type = "macvlan" but the nest
attrs are set to carry "veth"). Let the kernel handle that.
Parsing side is a little more specialized as we need to render and
insert a new kind of function which switches between what to parse
based on the selector. But code isn't too complicated.
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
Link: https://patch.msgid.link/20250515231650.1325372-7-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
		
	
			
		
			
				
	
	
		
			143 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 | 
						|
#ifndef __YNL_C_H
 | 
						|
#define __YNL_C_H 1
 | 
						|
 | 
						|
#include <stdbool.h>
 | 
						|
#include <stddef.h>
 | 
						|
#include <linux/genetlink.h>
 | 
						|
#include <linux/types.h>
 | 
						|
 | 
						|
#include "ynl-priv.h"
 | 
						|
 | 
						|
enum ynl_error_code {
 | 
						|
	YNL_ERROR_NONE = 0,
 | 
						|
	__YNL_ERRNO_END = 4096,
 | 
						|
	YNL_ERROR_INTERNAL,
 | 
						|
	YNL_ERROR_DUMP_INTER,
 | 
						|
	YNL_ERROR_EXPECT_ACK,
 | 
						|
	YNL_ERROR_EXPECT_MSG,
 | 
						|
	YNL_ERROR_UNEXPECT_MSG,
 | 
						|
	YNL_ERROR_ATTR_MISSING,
 | 
						|
	YNL_ERROR_ATTR_INVALID,
 | 
						|
	YNL_ERROR_UNKNOWN_NTF,
 | 
						|
	YNL_ERROR_INV_RESP,
 | 
						|
	YNL_ERROR_INPUT_INVALID,
 | 
						|
	YNL_ERROR_INPUT_TOO_BIG,
 | 
						|
	YNL_ERROR_SUBMSG_KEY,
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * struct ynl_error - error encountered by YNL
 | 
						|
 * @code:	errno (low values) or YNL error code (enum ynl_error_code)
 | 
						|
 * @attr_offs:	offset of bad attribute (for very advanced users)
 | 
						|
 * @msg:	error message
 | 
						|
 *
 | 
						|
 * Error information for when YNL operations fail.
 | 
						|
 * Users should interact with the err member of struct ynl_sock directly.
 | 
						|
 * The main exception to that rule is ynl_sock_create().
 | 
						|
 */
 | 
						|
struct ynl_error {
 | 
						|
	enum ynl_error_code code;
 | 
						|
	unsigned int attr_offs;
 | 
						|
	char msg[512];
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * struct ynl_family - YNL family info
 | 
						|
 * Family description generated by codegen. Pass to ynl_sock_create().
 | 
						|
 */
 | 
						|
struct ynl_family {
 | 
						|
/* private: */
 | 
						|
	const char *name;
 | 
						|
	size_t hdr_len;
 | 
						|
	bool is_classic;
 | 
						|
	__u16 classic_id;
 | 
						|
	const struct ynl_ntf_info *ntf_info;
 | 
						|
	unsigned int ntf_info_size;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * struct ynl_sock - YNL wrapped netlink socket
 | 
						|
 * @err: YNL error descriptor, cleared on every request.
 | 
						|
 */
 | 
						|
struct ynl_sock {
 | 
						|
	struct ynl_error err;
 | 
						|
 | 
						|
/* private: */
 | 
						|
	const struct ynl_family *family;
 | 
						|
	int socket;
 | 
						|
	__u32 seq;
 | 
						|
	__u32 portid;
 | 
						|
	__u16 family_id;
 | 
						|
 | 
						|
	unsigned int n_mcast_groups;
 | 
						|
	struct {
 | 
						|
		unsigned int id;
 | 
						|
		char name[GENL_NAMSIZ];
 | 
						|
	} *mcast_groups;
 | 
						|
 | 
						|
	struct ynl_ntf_base_type *ntf_first;
 | 
						|
	struct ynl_ntf_base_type **ntf_last_next;
 | 
						|
 | 
						|
	struct nlmsghdr *nlh;
 | 
						|
	const struct ynl_policy_nest *req_policy;
 | 
						|
	size_t req_hdr_len;
 | 
						|
	unsigned char *tx_buf;
 | 
						|
	unsigned char *rx_buf;
 | 
						|
	unsigned char raw_buf[];
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * struct ynl_string - parsed individual string
 | 
						|
 * @len: length of the string (excluding terminating character)
 | 
						|
 * @str: value of the string
 | 
						|
 *
 | 
						|
 * Parsed and nul-terminated string. This struct is only used for arrays of
 | 
						|
 * strings. Non-array string members are placed directly in respective types.
 | 
						|
 */
 | 
						|
struct ynl_string {
 | 
						|
	unsigned int len;
 | 
						|
	char str[];
 | 
						|
};
 | 
						|
 | 
						|
struct ynl_sock *
 | 
						|
ynl_sock_create(const struct ynl_family *yf, struct ynl_error *e);
 | 
						|
void ynl_sock_destroy(struct ynl_sock *ys);
 | 
						|
 | 
						|
#define ynl_dump_foreach(dump, iter)					\
 | 
						|
	for (typeof(dump->obj) *iter = &dump->obj;			\
 | 
						|
	     !ynl_dump_obj_is_last(iter);				\
 | 
						|
	     iter = ynl_dump_obj_next(iter))
 | 
						|
 | 
						|
/**
 | 
						|
 * ynl_dump_empty() - does the dump have no entries
 | 
						|
 * @dump: pointer to the dump list, as returned by a dump call
 | 
						|
 *
 | 
						|
 * Check if the dump is empty, i.e. contains no objects.
 | 
						|
 * Dump calls return NULL on error, and terminator element if empty.
 | 
						|
 */
 | 
						|
static inline bool ynl_dump_empty(void *dump)
 | 
						|
{
 | 
						|
	return dump == (void *)YNL_LIST_END;
 | 
						|
}
 | 
						|
 | 
						|
int ynl_subscribe(struct ynl_sock *ys, const char *grp_name);
 | 
						|
int ynl_socket_get_fd(struct ynl_sock *ys);
 | 
						|
int ynl_ntf_check(struct ynl_sock *ys);
 | 
						|
 | 
						|
/**
 | 
						|
 * ynl_has_ntf() - check if socket has *parsed* notifications
 | 
						|
 * @ys: active YNL socket
 | 
						|
 *
 | 
						|
 * Note that this does not take into account notifications sitting
 | 
						|
 * in netlink socket, just the notifications which have already been
 | 
						|
 * read and parsed (e.g. during a ynl_ntf_check() call).
 | 
						|
 */
 | 
						|
static inline bool ynl_has_ntf(struct ynl_sock *ys)
 | 
						|
{
 | 
						|
	return ys->ntf_last_next != &ys->ntf_first;
 | 
						|
}
 | 
						|
struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys);
 | 
						|
 | 
						|
void ynl_ntf_free(struct ynl_ntf_base_type *ntf);
 | 
						|
#endif
 |