xref: /linux/tools/net/ynl/lib/ynl.h (revision 2aceb896ee18ae35b21b14c978d8c2ef8c7b439d)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 #ifndef __YNL_C_H
3 #define __YNL_C_H 1
4 
5 #include <stddef.h>
6 #include <libmnl/libmnl.h>
7 #include <linux/genetlink.h>
8 #include <linux/types.h>
9 
10 struct mnl_socket;
11 struct nlmsghdr;
12 
13 /*
14  * User facing code
15  */
16 
17 struct ynl_ntf_base_type;
18 struct ynl_ntf_info;
19 struct ynl_sock;
20 
21 enum ynl_error_code {
22 	YNL_ERROR_NONE = 0,
23 	__YNL_ERRNO_END = 4096,
24 	YNL_ERROR_INTERNAL,
25 	YNL_ERROR_EXPECT_ACK,
26 	YNL_ERROR_EXPECT_MSG,
27 	YNL_ERROR_UNEXPECT_MSG,
28 	YNL_ERROR_ATTR_MISSING,
29 	YNL_ERROR_ATTR_INVALID,
30 	YNL_ERROR_UNKNOWN_NTF,
31 	YNL_ERROR_INV_RESP,
32 };
33 
34 /**
35  * struct ynl_error - error encountered by YNL
36  * @code:	errno (low values) or YNL error code (enum ynl_error_code)
37  * @attr_offs:	offset of bad attribute (for very advanced users)
38  * @msg:	error message
39  *
40  * Error information for when YNL operations fail.
41  * Users should interact with the err member of struct ynl_sock directly.
42  * The main exception to that rule is ynl_sock_create().
43  */
44 struct ynl_error {
45 	enum ynl_error_code code;
46 	unsigned int attr_offs;
47 	char msg[512];
48 };
49 
50 /**
51  * struct ynl_family - YNL family info
52  * Family description generated by codegen. Pass to ynl_sock_create().
53  */
54 struct ynl_family {
55 /* private: */
56 	const char *name;
57 	const struct ynl_ntf_info *ntf_info;
58 	unsigned int ntf_info_size;
59 };
60 
61 /**
62  * struct ynl_sock - YNL wrapped netlink socket
63  * @err: YNL error descriptor, cleared on every request.
64  */
65 struct ynl_sock {
66 	struct ynl_error err;
67 
68 /* private: */
69 	const struct ynl_family *family;
70 	struct mnl_socket *sock;
71 	__u32 seq;
72 	__u32 portid;
73 	__u16 family_id;
74 
75 	unsigned int n_mcast_groups;
76 	struct {
77 		unsigned int id;
78 		char name[GENL_NAMSIZ];
79 	} *mcast_groups;
80 
81 	struct ynl_ntf_base_type *ntf_first;
82 	struct ynl_ntf_base_type **ntf_last_next;
83 
84 	struct nlmsghdr *nlh;
85 	struct ynl_policy_nest *req_policy;
86 	unsigned char *tx_buf;
87 	unsigned char *rx_buf;
88 	unsigned char raw_buf[];
89 };
90 
91 struct ynl_sock *
92 ynl_sock_create(const struct ynl_family *yf, struct ynl_error *e);
93 void ynl_sock_destroy(struct ynl_sock *ys);
94 
95 #define ynl_dump_foreach(dump, iter)					\
96 	for (typeof(dump->obj) *iter = &dump->obj;			\
97 	     !ynl_dump_obj_is_last(iter);				\
98 	     iter = ynl_dump_obj_next(iter))
99 
100 int ynl_subscribe(struct ynl_sock *ys, const char *grp_name);
101 int ynl_socket_get_fd(struct ynl_sock *ys);
102 int ynl_ntf_check(struct ynl_sock *ys);
103 
104 /**
105  * ynl_has_ntf() - check if socket has *parsed* notifications
106  * @ys: active YNL socket
107  *
108  * Note that this does not take into account notifications sitting
109  * in netlink socket, just the notifications which have already been
110  * read and parsed (e.g. during a ynl_ntf_check() call).
111  */
112 static inline bool ynl_has_ntf(struct ynl_sock *ys)
113 {
114 	return ys->ntf_last_next != &ys->ntf_first;
115 }
116 struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys);
117 
118 void ynl_ntf_free(struct ynl_ntf_base_type *ntf);
119 
120 /*
121  * YNL internals / low level stuff
122  */
123 
124 /* Generic mnl helper code */
125 
126 enum ynl_policy_type {
127 	YNL_PT_REJECT = 1,
128 	YNL_PT_IGNORE,
129 	YNL_PT_NEST,
130 	YNL_PT_FLAG,
131 	YNL_PT_BINARY,
132 	YNL_PT_U8,
133 	YNL_PT_U16,
134 	YNL_PT_U32,
135 	YNL_PT_U64,
136 	YNL_PT_UINT,
137 	YNL_PT_NUL_STR,
138 };
139 
140 struct ynl_policy_attr {
141 	enum ynl_policy_type type;
142 	unsigned int len;
143 	const char *name;
144 	struct ynl_policy_nest *nest;
145 };
146 
147 struct ynl_policy_nest {
148 	unsigned int max_attr;
149 	struct ynl_policy_attr *table;
150 };
151 
152 struct ynl_parse_arg {
153 	struct ynl_sock *ys;
154 	struct ynl_policy_nest *rsp_policy;
155 	void *data;
156 };
157 
158 struct ynl_dump_list_type {
159 	struct ynl_dump_list_type *next;
160 	unsigned char data[] __attribute__ ((aligned (8)));
161 };
162 extern struct ynl_dump_list_type *YNL_LIST_END;
163 
164 static inline bool ynl_dump_obj_is_last(void *obj)
165 {
166 	unsigned long uptr = (unsigned long)obj;
167 
168 	uptr -= offsetof(struct ynl_dump_list_type, data);
169 	return uptr == (unsigned long)YNL_LIST_END;
170 }
171 
172 static inline void *ynl_dump_obj_next(void *obj)
173 {
174 	unsigned long uptr = (unsigned long)obj;
175 	struct ynl_dump_list_type *list;
176 
177 	uptr -= offsetof(struct ynl_dump_list_type, data);
178 	list = (void *)uptr;
179 	uptr = (unsigned long)list->next;
180 	uptr += offsetof(struct ynl_dump_list_type, data);
181 
182 	return (void *)uptr;
183 }
184 
185 struct ynl_ntf_base_type {
186 	__u16 family;
187 	__u8 cmd;
188 	struct ynl_ntf_base_type *next;
189 	void (*free)(struct ynl_ntf_base_type *ntf);
190 	unsigned char data[] __attribute__ ((aligned (8)));
191 };
192 
193 extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE];
194 
195 struct nlmsghdr *
196 ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
197 struct nlmsghdr *
198 ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
199 
200 int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
201 
202 int ynl_recv_ack(struct ynl_sock *ys, int ret);
203 int ynl_cb_null(const struct nlmsghdr *nlh, void *data);
204 
205 /* YNL specific helpers used by the auto-generated code */
206 
207 struct ynl_req_state {
208 	struct ynl_parse_arg yarg;
209 	mnl_cb_t cb;
210 	__u32 rsp_cmd;
211 };
212 
213 struct ynl_dump_state {
214 	struct ynl_sock *ys;
215 	struct ynl_policy_nest *rsp_policy;
216 	void *first;
217 	struct ynl_dump_list_type *last;
218 	size_t alloc_sz;
219 	mnl_cb_t cb;
220 	__u32 rsp_cmd;
221 };
222 
223 struct ynl_ntf_info {
224 	struct ynl_policy_nest *policy;
225 	mnl_cb_t cb;
226 	size_t alloc_sz;
227 	void (*free)(struct ynl_ntf_base_type *ntf);
228 };
229 
230 int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
231 	     struct ynl_req_state *yrs);
232 int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
233 		  struct ynl_dump_state *yds);
234 
235 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
236 int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
237 
238 #ifndef MNL_HAS_AUTO_SCALARS
239 static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr)
240 {
241 	if (mnl_attr_get_len(attr) == 4)
242 		return mnl_attr_get_u32(attr);
243 	return mnl_attr_get_u64(attr);
244 }
245 
246 static inline void
247 mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
248 {
249 	if ((uint32_t)data == (uint64_t)data)
250 		return mnl_attr_put_u32(nlh, type, data);
251 	return mnl_attr_put_u64(nlh, type, data);
252 }
253 #endif
254 #endif
255