xref: /openbmc/linux/tools/lib/bpf/nlattr.h (revision 3286f88f)
1 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 
3 /*
4  * NETLINK      Netlink attributes
5  *
6  * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
7  */
8 
9 #ifndef __LIBBPF_NLATTR_H
10 #define __LIBBPF_NLATTR_H
11 
12 #include <stdint.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <linux/netlink.h>
16 #include <linux/rtnetlink.h>
17 #include <linux/genetlink.h>
18 
19 /* avoid multiple definition of netlink features */
20 #define __LINUX_NETLINK_H
21 
22 /**
23  * Standard attribute types to specify validation policy
24  */
25 enum {
26 	LIBBPF_NLA_UNSPEC,	/**< Unspecified type, binary data chunk */
27 	LIBBPF_NLA_U8,		/**< 8 bit integer */
28 	LIBBPF_NLA_U16,		/**< 16 bit integer */
29 	LIBBPF_NLA_U32,		/**< 32 bit integer */
30 	LIBBPF_NLA_U64,		/**< 64 bit integer */
31 	LIBBPF_NLA_STRING,	/**< NUL terminated character string */
32 	LIBBPF_NLA_FLAG,	/**< Flag */
33 	LIBBPF_NLA_MSECS,	/**< Micro seconds (64bit) */
34 	LIBBPF_NLA_NESTED,	/**< Nested attributes */
35 	__LIBBPF_NLA_TYPE_MAX,
36 };
37 
38 #define LIBBPF_NLA_TYPE_MAX (__LIBBPF_NLA_TYPE_MAX - 1)
39 
40 /**
41  * @ingroup attr
42  * Attribute validation policy.
43  *
44  * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
45  */
46 struct libbpf_nla_policy {
47 	/** Type of attribute or LIBBPF_NLA_UNSPEC */
48 	uint16_t	type;
49 
50 	/** Minimal length of payload required */
51 	uint16_t	minlen;
52 
53 	/** Maximal length of payload allowed */
54 	uint16_t	maxlen;
55 };
56 
57 struct libbpf_nla_req {
58 	struct nlmsghdr nh;
59 	union {
60 		struct ifinfomsg ifinfo;
61 		struct tcmsg tc;
62 		struct genlmsghdr gnl;
63 	};
64 	char buf[128];
65 };
66 
67 /**
68  * @ingroup attr
69  * Iterate over a stream of attributes
70  * @arg pos	loop counter, set to current attribute
71  * @arg head	head of attribute stream
72  * @arg len	length of attribute stream
73  * @arg rem	initialized to len, holds bytes currently remaining in stream
74  */
75 #define libbpf_nla_for_each_attr(pos, head, len, rem) \
76 	for (pos = head, rem = len; \
77 	     nla_ok(pos, rem); \
78 	     pos = nla_next(pos, &(rem)))
79 
80 /**
81  * libbpf_nla_data - head of payload
82  * @nla: netlink attribute
83  */
84 static inline void *libbpf_nla_data(const struct nlattr *nla)
85 {
86 	return (void *)nla + NLA_HDRLEN;
87 }
88 
89 static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla)
90 {
91 	return *(uint8_t *)libbpf_nla_data(nla);
92 }
93 
94 static inline uint16_t libbpf_nla_getattr_u16(const struct nlattr *nla)
95 {
96 	return *(uint16_t *)libbpf_nla_data(nla);
97 }
98 
99 static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla)
100 {
101 	return *(uint32_t *)libbpf_nla_data(nla);
102 }
103 
104 static inline uint64_t libbpf_nla_getattr_u64(const struct nlattr *nla)
105 {
106 	return *(uint64_t *)libbpf_nla_data(nla);
107 }
108 
109 static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla)
110 {
111 	return (const char *)libbpf_nla_data(nla);
112 }
113 
114 /**
115  * libbpf_nla_len - length of payload
116  * @nla: netlink attribute
117  */
118 static inline int libbpf_nla_len(const struct nlattr *nla)
119 {
120 	return nla->nla_len - NLA_HDRLEN;
121 }
122 
123 int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
124 		     int len, struct libbpf_nla_policy *policy);
125 int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
126 			    struct nlattr *nla,
127 			    struct libbpf_nla_policy *policy);
128 
129 int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh);
130 
131 static inline struct nlattr *nla_data(struct nlattr *nla)
132 {
133 	return (struct nlattr *)((void *)nla + NLA_HDRLEN);
134 }
135 
136 static inline struct nlattr *req_tail(struct libbpf_nla_req *req)
137 {
138 	return (struct nlattr *)((void *)req + NLMSG_ALIGN(req->nh.nlmsg_len));
139 }
140 
141 static inline int nlattr_add(struct libbpf_nla_req *req, int type,
142 			     const void *data, int len)
143 {
144 	struct nlattr *nla;
145 
146 	if (NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > sizeof(*req))
147 		return -EMSGSIZE;
148 	if (!!data != !!len)
149 		return -EINVAL;
150 
151 	nla = req_tail(req);
152 	nla->nla_type = type;
153 	nla->nla_len = NLA_HDRLEN + len;
154 	if (data)
155 		memcpy(nla_data(nla), data, len);
156 	req->nh.nlmsg_len = NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(nla->nla_len);
157 	return 0;
158 }
159 
160 static inline struct nlattr *nlattr_begin_nested(struct libbpf_nla_req *req, int type)
161 {
162 	struct nlattr *tail;
163 
164 	tail = req_tail(req);
165 	if (nlattr_add(req, type | NLA_F_NESTED, NULL, 0))
166 		return NULL;
167 	return tail;
168 }
169 
170 static inline void nlattr_end_nested(struct libbpf_nla_req *req,
171 				     struct nlattr *tail)
172 {
173 	tail->nla_len = (void *)req_tail(req) - (void *)tail;
174 }
175 
176 #endif /* __LIBBPF_NLATTR_H */
177