return ret;
 }
 
-static int libbpf_netlink_send_recv(struct nlmsghdr *nh,
+static int libbpf_netlink_send_recv(struct libbpf_nla_req *req,
                                    __dump_nlmsg_t parse_msg,
                                    libbpf_dump_nlmsg_t parse_attr,
                                    void *cookie)
        if (sock < 0)
                return sock;
 
-       nh->nlmsg_pid = 0;
-       nh->nlmsg_seq = time(NULL);
+       req->nh.nlmsg_pid = 0;
+       req->nh.nlmsg_seq = time(NULL);
 
-       if (send(sock, nh, nh->nlmsg_len, 0) < 0) {
+       if (send(sock, req, req->nh.nlmsg_len, 0) < 0) {
                ret = -errno;
                goto out;
        }
 
-       ret = libbpf_netlink_recv(sock, nl_pid, nh->nlmsg_seq,
+       ret = libbpf_netlink_recv(sock, nl_pid, req->nh.nlmsg_seq,
                                  parse_msg, parse_attr, cookie);
 out:
        libbpf_netlink_close(sock);
 {
        struct nlattr *nla;
        int ret;
-       struct {
-               struct nlmsghdr  nh;
-               struct ifinfomsg ifinfo;
-               char             attrbuf[64];
-       } req;
+       struct libbpf_nla_req req;
 
        memset(&req, 0, sizeof(req));
        req.nh.nlmsg_len      = NLMSG_LENGTH(sizeof(struct ifinfomsg));
        req.ifinfo.ifi_family = AF_UNSPEC;
        req.ifinfo.ifi_index  = ifindex;
 
-       nla = nlattr_begin_nested(&req.nh, sizeof(req), IFLA_XDP);
+       nla = nlattr_begin_nested(&req, IFLA_XDP);
        if (!nla)
                return -EMSGSIZE;
-       ret = nlattr_add(&req.nh, sizeof(req), IFLA_XDP_FD, &fd, sizeof(fd));
+       ret = nlattr_add(&req, IFLA_XDP_FD, &fd, sizeof(fd));
        if (ret < 0)
                return ret;
        if (flags) {
-               ret = nlattr_add(&req.nh, sizeof(req), IFLA_XDP_FLAGS, &flags,
-                                sizeof(flags));
+               ret = nlattr_add(&req, IFLA_XDP_FLAGS, &flags, sizeof(flags));
                if (ret < 0)
                        return ret;
        }
        if (flags & XDP_FLAGS_REPLACE) {
-               ret = nlattr_add(&req.nh, sizeof(req), IFLA_XDP_EXPECTED_FD,
-                                &old_fd, sizeof(old_fd));
+               ret = nlattr_add(&req, IFLA_XDP_EXPECTED_FD, &old_fd,
+                                sizeof(old_fd));
                if (ret < 0)
                        return ret;
        }
-       nlattr_end_nested(&req.nh, nla);
+       nlattr_end_nested(&req, nla);
 
-       return libbpf_netlink_send_recv(&req.nh, NULL, NULL, NULL);
+       return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
 }
 
 int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
        struct xdp_id_md xdp_id = {};
        __u32 mask;
        int ret;
-       struct {
-               struct nlmsghdr  nh;
-               struct ifinfomsg ifm;
-       } req = {
-               .nh.nlmsg_len   = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-               .nh.nlmsg_type  = RTM_GETLINK,
-               .nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
-               .ifm.ifi_family = AF_PACKET,
+       struct libbpf_nla_req req = {
+               .nh.nlmsg_len      = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+               .nh.nlmsg_type     = RTM_GETLINK,
+               .nh.nlmsg_flags    = NLM_F_DUMP | NLM_F_REQUEST,
+               .ifinfo.ifi_family = AF_PACKET,
        };
 
        if (flags & ~XDP_FLAGS_MASK || !info_size)
        xdp_id.ifindex = ifindex;
        xdp_id.flags = flags;
 
-       ret = libbpf_netlink_send_recv(&req.nh, __dump_link_nlmsg,
+       ret = libbpf_netlink_send_recv(&req, __dump_link_nlmsg,
                                       get_xdp_info, &xdp_id);
        if (!ret) {
                size_t sz = min(info_size, sizeof(xdp_id.info));
        return libbpf_err(ret);
 }
 
-typedef int (*qdisc_config_t)(struct nlmsghdr *nh, struct tcmsg *t,
-                             size_t maxsz);
+typedef int (*qdisc_config_t)(struct libbpf_nla_req *req);
 
-static int clsact_config(struct nlmsghdr *nh, struct tcmsg *t, size_t maxsz)
+static int clsact_config(struct libbpf_nla_req *req)
 {
-       t->tcm_parent = TC_H_CLSACT;
-       t->tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
+       req->tc.tcm_parent = TC_H_CLSACT;
+       req->tc.tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
 
-       return nlattr_add(nh, maxsz, TCA_KIND, "clsact", sizeof("clsact"));
+       return nlattr_add(req, TCA_KIND, "clsact", sizeof("clsact"));
 }
 
 static int attach_point_to_config(struct bpf_tc_hook *hook,
 {
        qdisc_config_t config;
        int ret;
-       struct {
-               struct nlmsghdr nh;
-               struct tcmsg tc;
-               char buf[256];
-       } req;
+       struct libbpf_nla_req req;
 
        ret = attach_point_to_config(hook, &config);
        if (ret < 0)
        req.tc.tcm_family  = AF_UNSPEC;
        req.tc.tcm_ifindex = OPTS_GET(hook, ifindex, 0);
 
-       ret = config(&req.nh, &req.tc, sizeof(req));
+       ret = config(&req);
        if (ret < 0)
                return ret;
 
-       return libbpf_netlink_send_recv(&req.nh, NULL, NULL, NULL);
+       return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
 }
 
 static int tc_qdisc_create_excl(struct bpf_tc_hook *hook)
        return __get_tc_info(cookie, tc, tb, nh->nlmsg_flags & NLM_F_ECHO);
 }
 
-static int tc_add_fd_and_name(struct nlmsghdr *nh, size_t maxsz, int fd)
+static int tc_add_fd_and_name(struct libbpf_nla_req *req, int fd)
 {
        struct bpf_prog_info info = {};
        __u32 info_len = sizeof(info);
        if (ret < 0)
                return ret;
 
-       ret = nlattr_add(nh, maxsz, TCA_BPF_FD, &fd, sizeof(fd));
+       ret = nlattr_add(req, TCA_BPF_FD, &fd, sizeof(fd));
        if (ret < 0)
                return ret;
        len = snprintf(name, sizeof(name), "%s:[%u]", info.name, info.id);
                return -errno;
        if (len >= sizeof(name))
                return -ENAMETOOLONG;
-       return nlattr_add(nh, maxsz, TCA_BPF_NAME, name, len + 1);
+       return nlattr_add(req, TCA_BPF_NAME, name, len + 1);
 }
 
 int bpf_tc_attach(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
        __u32 protocol, bpf_flags, handle, priority, parent, prog_id, flags;
        int ret, ifindex, attach_point, prog_fd;
        struct bpf_cb_ctx info = {};
+       struct libbpf_nla_req req;
        struct nlattr *nla;
-       struct {
-               struct nlmsghdr nh;
-               struct tcmsg tc;
-               char buf[256];
-       } req;
 
        if (!hook || !opts ||
            !OPTS_VALID(hook, bpf_tc_hook) ||
                return libbpf_err(ret);
        req.tc.tcm_parent = parent;
 
-       ret = nlattr_add(&req.nh, sizeof(req), TCA_KIND, "bpf", sizeof("bpf"));
+       ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
        if (ret < 0)
                return libbpf_err(ret);
-       nla = nlattr_begin_nested(&req.nh, sizeof(req), TCA_OPTIONS);
+       nla = nlattr_begin_nested(&req, TCA_OPTIONS);
        if (!nla)
                return libbpf_err(-EMSGSIZE);
-       ret = tc_add_fd_and_name(&req.nh, sizeof(req), prog_fd);
+       ret = tc_add_fd_and_name(&req, prog_fd);
        if (ret < 0)
                return libbpf_err(ret);
        bpf_flags = TCA_BPF_FLAG_ACT_DIRECT;
-       ret = nlattr_add(&req.nh, sizeof(req), TCA_BPF_FLAGS, &bpf_flags,
-                        sizeof(bpf_flags));
+       ret = nlattr_add(&req, TCA_BPF_FLAGS, &bpf_flags, sizeof(bpf_flags));
        if (ret < 0)
                return libbpf_err(ret);
-       nlattr_end_nested(&req.nh, nla);
+       nlattr_end_nested(&req, nla);
 
        info.opts = opts;
 
-       ret = libbpf_netlink_send_recv(&req.nh, get_tc_info, NULL, &info);
+       ret = libbpf_netlink_send_recv(&req, get_tc_info, NULL, &info);
        if (ret < 0)
                return libbpf_err(ret);
        if (!info.processed)
 {
        __u32 protocol = 0, handle, priority, parent, prog_id, flags;
        int ret, ifindex, attach_point, prog_fd;
-       struct {
-               struct nlmsghdr nh;
-               struct tcmsg tc;
-               char buf[256];
-       } req;
+       struct libbpf_nla_req req;
 
        if (!hook ||
            !OPTS_VALID(hook, bpf_tc_hook) ||
        req.tc.tcm_parent = parent;
 
        if (!flush) {
-               ret = nlattr_add(&req.nh, sizeof(req), TCA_KIND,
-                                "bpf", sizeof("bpf"));
+               ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
                if (ret < 0)
                        return ret;
        }
 
-       return libbpf_netlink_send_recv(&req.nh, NULL, NULL, NULL);
+       return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
 }
 
 int bpf_tc_detach(const struct bpf_tc_hook *hook,
        __u32 protocol, handle, priority, parent, prog_id, flags;
        int ret, ifindex, attach_point, prog_fd;
        struct bpf_cb_ctx info = {};
-       struct {
-               struct nlmsghdr nh;
-               struct tcmsg tc;
-               char buf[256];
-       } req;
+       struct libbpf_nla_req req;
 
        if (!hook || !opts ||
            !OPTS_VALID(hook, bpf_tc_hook) ||
                return libbpf_err(ret);
        req.tc.tcm_parent = parent;
 
-       ret = nlattr_add(&req.nh, sizeof(req), TCA_KIND, "bpf", sizeof("bpf"));
+       ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
        if (ret < 0)
                return libbpf_err(ret);
 
        info.opts = opts;
 
-       ret = libbpf_netlink_send_recv(&req.nh, get_tc_info, NULL, &info);
+       ret = libbpf_netlink_send_recv(&req, get_tc_info, NULL, &info);
        if (ret < 0)
                return libbpf_err(ret);
        if (!info.processed)
 
 #include <string.h>
 #include <errno.h>
 #include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 
 /* avoid multiple definition of netlink features */
 #define __LINUX_NETLINK_H
        uint16_t        maxlen;
 };
 
+struct libbpf_nla_req {
+       struct nlmsghdr nh;
+       union {
+               struct ifinfomsg ifinfo;
+               struct tcmsg tc;
+       };
+       char buf[128];
+};
+
 /**
  * @ingroup attr
  * Iterate over a stream of attributes
        return (struct nlattr *)((char *)nla + NLA_HDRLEN);
 }
 
-static inline struct nlattr *nh_tail(struct nlmsghdr *nh)
+static inline struct nlattr *req_tail(struct libbpf_nla_req *req)
 {
-       return (struct nlattr *)((char *)nh + NLMSG_ALIGN(nh->nlmsg_len));
+       return (struct nlattr *)((char *)req + NLMSG_ALIGN(req->nh.nlmsg_len));
 }
 
-static inline int nlattr_add(struct nlmsghdr *nh, size_t maxsz, int type,
+static inline int nlattr_add(struct libbpf_nla_req *req, int type,
                             const void *data, int len)
 {
        struct nlattr *nla;
 
-       if (NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > maxsz)
+       if (NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > sizeof(*req))
                return -EMSGSIZE;
        if (!!data != !!len)
                return -EINVAL;
 
-       nla = nh_tail(nh);
+       nla = req_tail(req);
        nla->nla_type = type;
        nla->nla_len = NLA_HDRLEN + len;
        if (data)
                memcpy(nla_data(nla), data, len);
-       nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(nla->nla_len);
+       req->nh.nlmsg_len = NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(nla->nla_len);
        return 0;
 }
 
-static inline struct nlattr *nlattr_begin_nested(struct nlmsghdr *nh,
-                                                size_t maxsz, int type)
+static inline struct nlattr *nlattr_begin_nested(struct libbpf_nla_req *req, int type)
 {
        struct nlattr *tail;
 
-       tail = nh_tail(nh);
-       if (nlattr_add(nh, maxsz, type | NLA_F_NESTED, NULL, 0))
+       tail = req_tail(req);
+       if (nlattr_add(req, type | NLA_F_NESTED, NULL, 0))
                return NULL;
        return tail;
 }
 
-static inline void nlattr_end_nested(struct nlmsghdr *nh, struct nlattr *tail)
+static inline void nlattr_end_nested(struct libbpf_nla_req *req,
+                                    struct nlattr *tail)
 {
-       tail->nla_len = (char *)nh_tail(nh) - (char *)tail;
+       tail->nla_len = (char *)req_tail(req) - (char *)tail;
 }
 
 #endif /* __LIBBPF_NLATTR_H */