Skip to content

Commit 8bbb77b

Browse files
kkdwivediborkmann
authored andcommitted
libbpf: Add various netlink helpers
This change introduces a few helpers to wrap open coded attribute preparation in netlink.c. It also adds a libbpf_netlink_send_recv() that is useful to wrap send + recv handling in a generic way. Subsequent patch will also use this function for sending and receiving a netlink response. The libbpf_nl_get_link() helper has been removed instead, moving socket creation into the newly named libbpf_netlink_send_recv(). Every nested attribute's closure must happen using the helper nlattr_end_nested(), which sets its length properly. NLA_F_NESTED is enforced using nlattr_begin_nested() helper. Other simple attributes can be added directly. The maxsz parameter corresponds to the size of the request structure which is being filled in, so for instance with req being: struct { struct nlmsghdr nh; struct tcmsg t; char buf[4096]; } req; Then, maxsz should be sizeof(req). This change also converts the open coded attribute preparation with these helpers. Note that the only failure the internal call to nlattr_add() could result in the nested helper would be -EMSGSIZE, hence that is what we return to our caller. The libbpf_netlink_send_recv() call takes care of opening the socket, sending the netlink message, receiving the response, potentially invoking callbacks, and return errors if any, and then finally close the socket. This allows users to avoid identical socket setup code in different places. The only user of libbpf_nl_get_link() has been converted to make use of it. __bpf_set_link_xdp_fd_replace() has also been refactored to use it. Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> [ Daniel: major patch cleanup ] Signed-off-by: Daniel Borkmann <[email protected]> Reviewed-by: Toke Høiland-Jørgensen <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 513f485 commit 8bbb77b

File tree

2 files changed

+120
-89
lines changed

2 files changed

+120
-89
lines changed

tools/lib/bpf/netlink.c

Lines changed: 72 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,14 @@ static int libbpf_netlink_open(__u32 *nl_pid)
7373
return ret;
7474
}
7575

76-
static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
77-
__dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn,
78-
void *cookie)
76+
static void libbpf_netlink_close(int sock)
77+
{
78+
close(sock);
79+
}
80+
81+
static int libbpf_netlink_recv(int sock, __u32 nl_pid, int seq,
82+
__dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn,
83+
void *cookie)
7984
{
8085
bool multipart = true;
8186
struct nlmsgerr *err;
@@ -131,72 +136,72 @@ static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
131136
return ret;
132137
}
133138

139+
static int libbpf_netlink_send_recv(struct nlmsghdr *nh,
140+
__dump_nlmsg_t parse_msg,
141+
libbpf_dump_nlmsg_t parse_attr,
142+
void *cookie)
143+
{
144+
__u32 nl_pid = 0;
145+
int sock, ret;
146+
147+
sock = libbpf_netlink_open(&nl_pid);
148+
if (sock < 0)
149+
return sock;
150+
151+
nh->nlmsg_pid = 0;
152+
nh->nlmsg_seq = time(NULL);
153+
154+
if (send(sock, nh, nh->nlmsg_len, 0) < 0) {
155+
ret = -errno;
156+
goto out;
157+
}
158+
159+
ret = libbpf_netlink_recv(sock, nl_pid, nh->nlmsg_seq,
160+
parse_msg, parse_attr, cookie);
161+
out:
162+
libbpf_netlink_close(sock);
163+
return ret;
164+
}
165+
134166
static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
135167
__u32 flags)
136168
{
137-
int sock, seq = 0, ret;
138-
struct nlattr *nla, *nla_xdp;
169+
struct nlattr *nla;
170+
int ret;
139171
struct {
140172
struct nlmsghdr nh;
141173
struct ifinfomsg ifinfo;
142174
char attrbuf[64];
143175
} req;
144-
__u32 nl_pid = 0;
145-
146-
sock = libbpf_netlink_open(&nl_pid);
147-
if (sock < 0)
148-
return sock;
149176

150177
memset(&req, 0, sizeof(req));
151-
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
152-
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
153-
req.nh.nlmsg_type = RTM_SETLINK;
154-
req.nh.nlmsg_pid = 0;
155-
req.nh.nlmsg_seq = ++seq;
178+
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
179+
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
180+
req.nh.nlmsg_type = RTM_SETLINK;
156181
req.ifinfo.ifi_family = AF_UNSPEC;
157-
req.ifinfo.ifi_index = ifindex;
158-
159-
/* started nested attribute for XDP */
160-
nla = (struct nlattr *)(((char *)&req)
161-
+ NLMSG_ALIGN(req.nh.nlmsg_len));
162-
nla->nla_type = NLA_F_NESTED | IFLA_XDP;
163-
nla->nla_len = NLA_HDRLEN;
164-
165-
/* add XDP fd */
166-
nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
167-
nla_xdp->nla_type = IFLA_XDP_FD;
168-
nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
169-
memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
170-
nla->nla_len += nla_xdp->nla_len;
171-
172-
/* if user passed in any flags, add those too */
182+
req.ifinfo.ifi_index = ifindex;
183+
184+
nla = nlattr_begin_nested(&req.nh, sizeof(req), IFLA_XDP);
185+
if (!nla)
186+
return -EMSGSIZE;
187+
ret = nlattr_add(&req.nh, sizeof(req), IFLA_XDP_FD, &fd, sizeof(fd));
188+
if (ret < 0)
189+
return ret;
173190
if (flags) {
174-
nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
175-
nla_xdp->nla_type = IFLA_XDP_FLAGS;
176-
nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
177-
memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
178-
nla->nla_len += nla_xdp->nla_len;
191+
ret = nlattr_add(&req.nh, sizeof(req), IFLA_XDP_FLAGS, &flags,
192+
sizeof(flags));
193+
if (ret < 0)
194+
return ret;
179195
}
180-
181196
if (flags & XDP_FLAGS_REPLACE) {
182-
nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
183-
nla_xdp->nla_type = IFLA_XDP_EXPECTED_FD;
184-
nla_xdp->nla_len = NLA_HDRLEN + sizeof(old_fd);
185-
memcpy((char *)nla_xdp + NLA_HDRLEN, &old_fd, sizeof(old_fd));
186-
nla->nla_len += nla_xdp->nla_len;
197+
ret = nlattr_add(&req.nh, sizeof(req), IFLA_XDP_EXPECTED_FD,
198+
&old_fd, sizeof(old_fd));
199+
if (ret < 0)
200+
return ret;
187201
}
202+
nlattr_end_nested(&req.nh, nla);
188203

189-
req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
190-
191-
if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
192-
ret = -errno;
193-
goto cleanup;
194-
}
195-
ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL);
196-
197-
cleanup:
198-
close(sock);
199-
return ret;
204+
return libbpf_netlink_send_recv(&req.nh, NULL, NULL, NULL);
200205
}
201206

202207
int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
@@ -212,9 +217,7 @@ int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
212217
flags |= XDP_FLAGS_REPLACE;
213218
}
214219

215-
return __bpf_set_link_xdp_fd_replace(ifindex, fd,
216-
old_fd,
217-
flags);
220+
return __bpf_set_link_xdp_fd_replace(ifindex, fd, old_fd, flags);
218221
}
219222

220223
int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
@@ -231,6 +234,7 @@ static int __dump_link_nlmsg(struct nlmsghdr *nlh,
231234

232235
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
233236
attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
237+
234238
if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
235239
return -LIBBPF_ERRNO__NLPARSE;
236240

@@ -282,16 +286,21 @@ static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
282286
return 0;
283287
}
284288

285-
static int libbpf_nl_get_link(int sock, unsigned int nl_pid,
286-
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie);
287-
288289
int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
289290
size_t info_size, __u32 flags)
290291
{
291292
struct xdp_id_md xdp_id = {};
292-
int sock, ret;
293-
__u32 nl_pid = 0;
294293
__u32 mask;
294+
int ret;
295+
struct {
296+
struct nlmsghdr nh;
297+
struct ifinfomsg ifm;
298+
} req = {
299+
.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
300+
.nh.nlmsg_type = RTM_GETLINK,
301+
.nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
302+
.ifm.ifi_family = AF_PACKET,
303+
};
295304

296305
if (flags & ~XDP_FLAGS_MASK || !info_size)
297306
return -EINVAL;
@@ -302,22 +311,18 @@ int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
302311
if (flags && flags & mask)
303312
return -EINVAL;
304313

305-
sock = libbpf_netlink_open(&nl_pid);
306-
if (sock < 0)
307-
return sock;
308-
309314
xdp_id.ifindex = ifindex;
310315
xdp_id.flags = flags;
311316

312-
ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_info, &xdp_id);
317+
ret = libbpf_netlink_send_recv(&req.nh, __dump_link_nlmsg,
318+
get_xdp_info, &xdp_id);
313319
if (!ret) {
314320
size_t sz = min(info_size, sizeof(xdp_id.info));
315321

316322
memcpy(info, &xdp_id.info, sz);
317323
memset((void *) info + sz, 0, info_size - sz);
318324
}
319325

320-
close(sock);
321326
return ret;
322327
}
323328

@@ -348,25 +353,3 @@ int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
348353

349354
return ret;
350355
}
351-
352-
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
353-
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
354-
{
355-
struct {
356-
struct nlmsghdr nlh;
357-
struct ifinfomsg ifm;
358-
} req = {
359-
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
360-
.nlh.nlmsg_type = RTM_GETLINK,
361-
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
362-
.ifm.ifi_family = AF_PACKET,
363-
};
364-
int seq = time(NULL);
365-
366-
req.nlh.nlmsg_seq = seq;
367-
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
368-
return -errno;
369-
370-
return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
371-
dump_link_nlmsg, cookie);
372-
}

tools/lib/bpf/nlattr.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
#define __LIBBPF_NLATTR_H
1111

1212
#include <stdint.h>
13+
#include <string.h>
14+
#include <errno.h>
1315
#include <linux/netlink.h>
16+
1417
/* avoid multiple definition of netlink features */
1518
#define __LINUX_NETLINK_H
1619

@@ -103,4 +106,49 @@ int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
103106

104107
int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh);
105108

109+
static inline struct nlattr *nla_data(struct nlattr *nla)
110+
{
111+
return (struct nlattr *)((char *)nla + NLA_HDRLEN);
112+
}
113+
114+
static inline struct nlattr *nh_tail(struct nlmsghdr *nh)
115+
{
116+
return (struct nlattr *)((char *)nh + NLMSG_ALIGN(nh->nlmsg_len));
117+
}
118+
119+
static inline int nlattr_add(struct nlmsghdr *nh, size_t maxsz, int type,
120+
const void *data, int len)
121+
{
122+
struct nlattr *nla;
123+
124+
if (NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > maxsz)
125+
return -EMSGSIZE;
126+
if (!!data != !!len)
127+
return -EINVAL;
128+
129+
nla = nh_tail(nh);
130+
nla->nla_type = type;
131+
nla->nla_len = NLA_HDRLEN + len;
132+
if (data)
133+
memcpy(nla_data(nla), data, len);
134+
nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(nla->nla_len);
135+
return 0;
136+
}
137+
138+
static inline struct nlattr *nlattr_begin_nested(struct nlmsghdr *nh,
139+
size_t maxsz, int type)
140+
{
141+
struct nlattr *tail;
142+
143+
tail = nh_tail(nh);
144+
if (nlattr_add(nh, maxsz, type | NLA_F_NESTED, NULL, 0))
145+
return NULL;
146+
return tail;
147+
}
148+
149+
static inline void nlattr_end_nested(struct nlmsghdr *nh, struct nlattr *tail)
150+
{
151+
tail->nla_len = (char *)nh_tail(nh) - (char *)tail;
152+
}
153+
106154
#endif /* __LIBBPF_NLATTR_H */

0 commit comments

Comments
 (0)