summaryrefslogtreecommitdiff
path: root/tools/net/ynl/lib/ynl.h
blob: e974378e3b8c79001c2e1fe70ccf1800d83279f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
#ifndef __YNL_C_H
#define __YNL_C_H 1

#include <stddef.h>
#include <libmnl/libmnl.h>
#include <linux/genetlink.h>
#include <linux/types.h>

struct mnl_socket;
struct nlmsghdr;

/*
 * User facing code
 */

struct ynl_ntf_base_type;
struct ynl_ntf_info;
struct ynl_sock;

enum ynl_error_code {
	YNL_ERROR_NONE = 0,
	__YNL_ERRNO_END = 4096,
	YNL_ERROR_INTERNAL,
	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,
};

/**
 * 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;
	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;
	struct mnl_socket *sock;
	__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;
	struct ynl_policy_nest *req_policy;
	unsigned char *tx_buf;
	unsigned char *rx_buf;
	unsigned char raw_buf[];
};

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))

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);

/*
 * YNL internals / low level stuff
 */

/* Generic mnl helper code */

enum ynl_policy_type {
	YNL_PT_REJECT = 1,
	YNL_PT_IGNORE,
	YNL_PT_NEST,
	YNL_PT_FLAG,
	YNL_PT_BINARY,
	YNL_PT_U8,
	YNL_PT_U16,
	YNL_PT_U32,
	YNL_PT_U64,
	YNL_PT_UINT,
	YNL_PT_NUL_STR,
	YNL_PT_BITFIELD32,
};

struct ynl_policy_attr {
	enum ynl_policy_type type;
	unsigned int len;
	const char *name;
	struct ynl_policy_nest *nest;
};

struct ynl_policy_nest {
	unsigned int max_attr;
	struct ynl_policy_attr *table;
};

struct ynl_parse_arg {
	struct ynl_sock *ys;
	struct ynl_policy_nest *rsp_policy;
	void *data;
};

struct ynl_dump_list_type {
	struct ynl_dump_list_type *next;
	unsigned char data[] __attribute__((aligned(8)));
};
extern struct ynl_dump_list_type *YNL_LIST_END;

static inline bool ynl_dump_obj_is_last(void *obj)
{
	unsigned long uptr = (unsigned long)obj;

	uptr -= offsetof(struct ynl_dump_list_type, data);
	return uptr == (unsigned long)YNL_LIST_END;
}

static inline void *ynl_dump_obj_next(void *obj)
{
	unsigned long uptr = (unsigned long)obj;
	struct ynl_dump_list_type *list;

	uptr -= offsetof(struct ynl_dump_list_type, data);
	list = (void *)uptr;
	uptr = (unsigned long)list->next;
	uptr += offsetof(struct ynl_dump_list_type, data);

	return (void *)uptr;
}

struct ynl_ntf_base_type {
	__u16 family;
	__u8 cmd;
	struct ynl_ntf_base_type *next;
	void (*free)(struct ynl_ntf_base_type *ntf);
	unsigned char data[] __attribute__((aligned(8)));
};

extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE];

struct nlmsghdr *
ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
struct nlmsghdr *
ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);

int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);

int ynl_recv_ack(struct ynl_sock *ys, int ret);
int ynl_cb_null(const struct nlmsghdr *nlh, void *data);

/* YNL specific helpers used by the auto-generated code */

struct ynl_req_state {
	struct ynl_parse_arg yarg;
	mnl_cb_t cb;
	__u32 rsp_cmd;
};

struct ynl_dump_state {
	struct ynl_sock *ys;
	struct ynl_policy_nest *rsp_policy;
	void *first;
	struct ynl_dump_list_type *last;
	size_t alloc_sz;
	mnl_cb_t cb;
	__u32 rsp_cmd;
};

struct ynl_ntf_info {
	struct ynl_policy_nest *policy;
	mnl_cb_t cb;
	size_t alloc_sz;
	void (*free)(struct ynl_ntf_base_type *ntf);
};

int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
	     struct ynl_req_state *yrs);
int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
		  struct ynl_dump_state *yds);

void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);

#ifndef MNL_HAS_AUTO_SCALARS
static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr)
{
	if (mnl_attr_get_len(attr) == 4)
		return mnl_attr_get_u32(attr);
	return mnl_attr_get_u64(attr);
}

static inline void
mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
{
	if ((uint32_t)data == (uint64_t)data)
		return mnl_attr_put_u32(nlh, type, data);
	return mnl_attr_put_u64(nlh, type, data);
}
#endif
#endif