diff --git a/src/include/ifaddrs.h b/src/include/ifaddrs.h deleted file mode 100644 index 4f1352d058..0000000000 --- a/src/include/ifaddrs.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _IFADDRS_H -#define _IFADDRS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -struct ifaddrs { - struct ifaddrs *ifa_next; - char *ifa_name; - unsigned ifa_flags; - struct sockaddr *ifa_addr; - struct sockaddr *ifa_netmask; - union { - struct sockaddr *ifu_broadaddr; - struct sockaddr *ifu_dstaddr; - } ifa_ifu; - void *ifa_data; -}; -#define ifa_broadaddr ifa_ifu.ifu_broadaddr -#define ifa_dstaddr ifa_ifu.ifu_dstaddr - -void freeifaddrs(struct ifaddrs *); -int getifaddrs(struct ifaddrs **); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/include/ifaddrs.c b/src/include/netns_ifaddrs.c similarity index 57% rename from src/include/ifaddrs.c rename to src/include/netns_ifaddrs.c index ee52bf397c..3fbb10520f 100644 --- a/src/include/ifaddrs.c +++ b/src/include/netns_ifaddrs.c @@ -1,15 +1,30 @@ #define _GNU_SOURCE +#include #include +#include +#include +#include +#include #include #include -#include +#include +#include #include +#include +#include #include #include #include #include -#include "ifaddrs.h" +#include "nl.h" +#include "macro.h" +#include "netns_ifaddrs.h" + +#ifndef NETNS_RTA +#define NETNS_RTA(r) \ + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg)))) +#endif #define IFADDRS_HASH_SIZE 64 @@ -47,10 +62,11 @@ #define __RTA_DATA(rta) ((void *)((char *)(rta) + sizeof(struct rtattr))) -/* getifaddrs() reports hardware addresses with PF_PACKET that implies - * struct sockaddr_ll. But e.g. Infiniband socket address length is - * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct - * to extend ssl_addr - callers should be able to still use it. */ +/* getifaddrs() reports hardware addresses with PF_PACKET that implies struct + * sockaddr_ll. But e.g. Infiniband socket address length is longer than + * sockaddr_ll.ssl_addr[8] can hold. Use this hack struct to extend ssl_addr - + * callers should be able to still use it. + */ struct sockaddr_ll_hack { unsigned short sll_family, sll_protocol; int sll_ifindex; @@ -67,7 +83,7 @@ union sockany { }; struct ifaddrs_storage { - struct ifaddrs ifa; + struct netns_ifaddrs ifa; struct ifaddrs_storage *hash_next; union sockany addr, netmask, ifu; unsigned int index; @@ -80,17 +96,6 @@ struct ifaddrs_ctx { struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE]; }; -void freeifaddrs(struct ifaddrs *ifp) -{ - struct ifaddrs *n; - - while (ifp) { - n = ifp->ifa_next; - free(ifp); - ifp = n; - } -} - static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex) { @@ -105,7 +110,8 @@ static void copy_addr(struct sockaddr **r, int af, union sockany *sa, case AF_INET6: dst = (uint8_t *)&sa->v6.sin6_addr; len = 16; - if (__IN6_IS_ADDR_LINKLOCAL(addr) || __IN6_IS_ADDR_MC_LINKLOCAL(addr)) + if (__IN6_IS_ADDR_LINKLOCAL(addr) || + __IN6_IS_ADDR_MC_LINKLOCAL(addr)) sa->v6.sin6_scope_id = ifindex; break; default: @@ -157,7 +163,7 @@ static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, *r = &sa->sa; } -static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) +static int nl_msg_to_ifaddr(void *pctx, bool *netnsid_aware, struct nlmsghdr *h) { struct ifaddrs_storage *ifs, *ifs0; struct rtattr *rta; @@ -169,7 +175,6 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) if (h->nlmsg_type == RTM_NEWLINK) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" - for (rta = __NLMSG_RTA(h, sizeof(*ifi)); __NLMSG_RTAOK(rta, h); rta = __RTA_NEXT(rta)) { if (rta->rta_type != IFLA_STATS) @@ -178,7 +183,6 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) stats_len = __RTA_DATALEN(rta); break; } - #pragma GCC diagnostic pop } else { for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; @@ -197,9 +201,9 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" - if (h->nlmsg_type == RTM_NEWLINK) { ifs->index = ifi->ifi_index; + ifs->ifa.ifa_ifindex = ifi->ifi_index; ifs->ifa.ifa_flags = ifi->ifi_flags; for (rta = __NLMSG_RTA(h, sizeof(*ifi)); __NLMSG_RTAOK(rta, h); @@ -218,7 +222,7 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) ifi->ifi_index, ifi->ifi_type); break; case IFLA_BROADCAST: - copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, + copy_lladdr(&ifs->ifa.__ifa_broadaddr, &ifs->ifu, __RTA_DATA(rta), __RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); break; @@ -227,6 +231,13 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) memcpy(ifs->ifa.ifa_data, __RTA_DATA(rta), __RTA_DATALEN(rta)); break; + case IFLA_MTU: + memcpy(&ifs->ifa.ifa_mtu, __RTA_DATA(rta), + sizeof(int)); + break; + case IFLA_TARGET_NETNSID: + *netnsid_aware = true; + break; } } @@ -237,6 +248,8 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) } } else { ifs->ifa.ifa_name = ifs0->ifa.ifa_name; + ifs->ifa.ifa_mtu = ifs0->ifa.ifa_mtu; + ifs->ifa.ifa_ifindex = ifs0->ifa.ifa_ifindex; ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags; for (rta = __NLMSG_RTA(h, sizeof(*ifa)); __NLMSG_RTAOK(rta, h); @@ -244,11 +257,11 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) switch (rta->rta_type) { case IFA_ADDRESS: /* If ifa_addr is already set we, received an - * IFA_LOCAL before so treat this as destination - * address. + * IFA_LOCAL before so treat this as + * destination address. */ if (ifs->ifa.ifa_addr) - copy_addr(&ifs->ifa.ifa_dstaddr, + copy_addr(&ifs->ifa.__ifa_dstaddr, ifa->ifa_family, &ifs->ifu, __RTA_DATA(rta), __RTA_DATALEN(rta), @@ -261,19 +274,19 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) ifa->ifa_index); break; case IFA_BROADCAST: - copy_addr(&ifs->ifa.ifa_broadaddr, + copy_addr(&ifs->ifa.__ifa_broadaddr, ifa->ifa_family, &ifs->ifu, __RTA_DATA(rta), __RTA_DATALEN(rta), ifa->ifa_index); break; case IFA_LOCAL: /* If ifa_addr is set and we get IFA_LOCAL, - * assume we have a point-to-point network. Move - * address to correct field. + * assume we have a point-to-point network. + * Move address to correct field. */ if (ifs->ifa.ifa_addr) { ifs->ifu = ifs->addr; - ifs->ifa.ifa_dstaddr = &ifs->ifu.sa; + ifs->ifa.__ifa_dstaddr = &ifs->ifu.sa; memset(&ifs->addr, 0, sizeof(ifs->addr)); } @@ -289,14 +302,18 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) ifs->ifa.ifa_name = ifs->name; } break; + case IFA_TARGET_NETNSID: + *netnsid_aware = true; + break; } } - if (ifs->ifa.ifa_addr) + if (ifs->ifa.ifa_addr) { gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen); + ifs->ifa.ifa_prefixlen = ifa->ifa_prefixlen; + } } - #pragma GCC diagnostic pop if (ifs->ifa.ifa_name) { @@ -314,11 +331,49 @@ static int nl_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) return 0; } -static int __nl_recv(int fd, unsigned int seq, int type, int af, - int (*cb)(void *ctx, struct nlmsghdr *h), - void *ctx) +static int __ifaddrs_netlink_send(int fd, struct nlmsghdr *nlmsghdr) +{ + int ret; + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = nlmsghdr, + .iov_len = nlmsghdr->nlmsg_len, + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + + ret = sendmsg(fd, &msg, MSG_NOSIGNAL); + if (ret < 0) + return -1; + + return ret; +} + +static int __ifaddrs_netlink_recv(int fd, unsigned int seq, int type, int af, + __s32 netns_id, bool *netnsid_aware, + int (*cb)(void *ctx, bool *netnsid_aware, + struct nlmsghdr *h), + void *ctx) { - struct nlmsghdr *h; + char getlink_buf[__NETLINK_ALIGN(sizeof(struct nlmsghdr)) + + __NETLINK_ALIGN(sizeof(struct ifinfomsg)) + + __NETLINK_ALIGN(1024)]; + char getaddr_buf[__NETLINK_ALIGN(sizeof(struct nlmsghdr)) + + __NETLINK_ALIGN(sizeof(struct ifaddrmsg)) + + __NETLINK_ALIGN(1024)]; + char *buf; + struct nlmsghdr *hdr; + struct ifinfomsg *ifi_msg; + struct ifaddrmsg *ifa_msg; union { uint8_t buf[8192]; struct { @@ -327,17 +382,50 @@ static int __nl_recv(int fd, unsigned int seq, int type, int af, } req; struct nlmsghdr reply; } u; - int r, ret; - - memset(&u.req, 0, sizeof(u.req)); - u.req.nlh.nlmsg_len = sizeof(u.req); - u.req.nlh.nlmsg_type = type; - u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; - u.req.nlh.nlmsg_seq = seq; - u.req.g.rtgen_family = af; - r = send(fd, &u.req, sizeof(u.req), 0); + int r, property, ret; + + if (type == RTM_GETLINK) + buf = getlink_buf; + else if (type == RTM_GETADDR) + buf = getaddr_buf; + else + return -1; + + memset(buf, 0, sizeof(*buf)); + hdr = (struct nlmsghdr *)buf; + if (type == RTM_GETLINK) + ifi_msg = (struct ifinfomsg *)__NLMSG_DATA(hdr); + else + ifa_msg = (struct ifaddrmsg *)__NLMSG_DATA(hdr); + + if (type == RTM_GETLINK) + hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifi_msg)); + else + hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifa_msg)); + + hdr->nlmsg_type = type; + hdr->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + hdr->nlmsg_pid = 0; + hdr->nlmsg_seq = seq; + if (type == RTM_GETLINK) + ifi_msg->ifi_family = af; + else + ifa_msg->ifa_family = af; + + errno = EINVAL; + if (type == RTM_GETLINK) + property = IFLA_TARGET_NETNSID; + else if (type == RTM_GETADDR) + property = IFA_TARGET_NETNSID; + else + return -1; + + if (netns_id >= 0) + addattr(hdr, 1024, property, &netns_id, sizeof(netns_id)); + + r = __ifaddrs_netlink_send(fd, hdr); if (r < 0) - return r; + return -1; for (;;) { r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT); @@ -346,17 +434,17 @@ static int __nl_recv(int fd, unsigned int seq, int type, int af, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" - for (h = &u.reply; __NLMSG_OK(h, (void *)&u.buf[r]); - h = __NLMSG_NEXT(h)) { - if (h->nlmsg_type == NLMSG_DONE) + for (hdr = &u.reply; __NLMSG_OK(hdr, (void *)&u.buf[r]); + hdr = __NLMSG_NEXT(hdr)) { + if (hdr->nlmsg_type == NLMSG_DONE) return 0; - if (h->nlmsg_type == NLMSG_ERROR) { + if (hdr->nlmsg_type == NLMSG_ERROR) { errno = EINVAL; return -1; } - ret = cb(ctx, h); + ret = cb(ctx, netnsid_aware, hdr); if (ret) return ret; } @@ -364,27 +452,81 @@ static int __nl_recv(int fd, unsigned int seq, int type, int af, } } -static int __rtnl_enumerate(int link_af, int addr_af, - int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +static int __rtnl_enumerate(int link_af, int addr_af, __s32 netns_id, + bool *netnsid_aware, + int (*cb)(void *ctx, bool *netnsid_aware, struct nlmsghdr *h), + void *ctx) { int fd, r, saved_errno; + bool getaddr_netnsid_aware = false, getlink_netnsid_aware = false; fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); if (fd < 0) return -1; - r = __nl_recv(fd, 1, RTM_GETLINK, link_af, cb, ctx); + r = __ifaddrs_netlink_recv(fd, 1, RTM_GETLINK, link_af, netns_id, + &getlink_netnsid_aware, cb, ctx); if (!r) - r = __nl_recv(fd, 2, RTM_GETADDR, addr_af, cb, ctx); + r = __ifaddrs_netlink_recv(fd, 2, RTM_GETADDR, addr_af, netns_id, + &getaddr_netnsid_aware, cb, ctx); saved_errno = errno; close(fd); errno = saved_errno; + if (getaddr_netnsid_aware && getlink_netnsid_aware) + *netnsid_aware = true; + else + *netnsid_aware = false; + return r; } -int getifaddrs(struct ifaddrs **ifap) +/* Get a pointer to the address structure from a sockaddr. */ +static void *get_addr_ptr(struct sockaddr *sockaddr_ptr) +{ + if (sockaddr_ptr->sa_family == AF_INET) + return &((struct sockaddr_in *)sockaddr_ptr)->sin_addr; + + if (sockaddr_ptr->sa_family == AF_INET6) + return &((struct sockaddr_in6 *)sockaddr_ptr)->sin6_addr; + + return NULL; +} + +static char *get_packet_address(struct sockaddr *sockaddr_ptr, char *buf, size_t buflen) +{ + char *slider = buf; + unsigned char *m = ((struct sockaddr_ll *)sockaddr_ptr)->sll_addr; + unsigned char n = ((struct sockaddr_ll *)sockaddr_ptr)->sll_halen; + + for (unsigned char i = 0; i < n; i++) { + int ret; + + ret = snprintf(slider, buflen, "%02x%s", m[i], (i + 1) < n ? ":" : ""); + if (ret < 0 || (size_t)ret >= buflen) + return NULL; + + buflen -= ret; + slider = (slider + ret); + } + + return buf; +} + +void netns_freeifaddrs(struct netns_ifaddrs *ifp) +{ + struct netns_ifaddrs *n; + + while (ifp) { + n = ifp->ifa_next; + free(ifp); + ifp = n; + } +} + +int netns_getifaddrs(struct netns_ifaddrs **ifap, __s32 netns_id, + bool *netnsid_aware) { int r, saved_errno; struct ifaddrs_ctx _ctx; @@ -392,10 +534,11 @@ int getifaddrs(struct ifaddrs **ifap) memset(ctx, 0, sizeof *ctx); - r = __rtnl_enumerate(AF_UNSPEC, AF_UNSPEC, nl_msg_to_ifaddr, ctx); + r = __rtnl_enumerate(AF_UNSPEC, AF_UNSPEC, netns_id, netnsid_aware, + nl_msg_to_ifaddr, ctx); saved_errno = errno; if (r < 0) - freeifaddrs(&ctx->first->ifa); + netns_freeifaddrs(&ctx->first->ifa); else *ifap = &ctx->first->ifa; errno = saved_errno; diff --git a/src/include/netns_ifaddrs.h b/src/include/netns_ifaddrs.h new file mode 100644 index 0000000000..ee9236ed9f --- /dev/null +++ b/src/include/netns_ifaddrs.h @@ -0,0 +1,53 @@ +#ifndef _LXC_NETNS_IFADDRS_H +#define _LXC_NETNS_IFADDRS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include + +struct netns_ifaddrs { + struct netns_ifaddrs *ifa_next; + + /* Can - but shouldn't be - NULL. */ + char *ifa_name; + + /* This field is not present struct ifaddrs. */ + int ifa_ifindex; + + unsigned ifa_flags; + + /* This field is not present struct ifaddrs. */ + int ifa_mtu; + + /* This field is not present struct ifaddrs. */ + int ifa_prefixlen; + + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + union { + struct sockaddr *ifu_broadaddr; + struct sockaddr *ifu_dstaddr; + } ifa_ifu; + + /* If you don't know what this is for don't touch it. */ + void *ifa_data; +}; + +#define __ifa_broadaddr ifa_ifu.ifu_broadaddr +#define __ifa_dstaddr ifa_ifu.ifu_dstaddr + +extern void netns_freeifaddrs(struct netns_ifaddrs *); +extern int netns_getifaddrs(struct netns_ifaddrs **ifap, __s32 netns_id, + bool *netnsid_aware); + +#ifdef __cplusplus +} +#endif + +#endif /* _LXC_NETNS_IFADDRS_H */ diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 51c871eb6e..690486d34d 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -14,6 +14,7 @@ noinst_HEADERS = api_extensions.h \ criu.h \ error.h \ file_utils.h \ + ../include/netns_ifaddrs.h \ initutils.h \ list.h \ log.h \ @@ -41,10 +42,6 @@ noinst_HEADERS = api_extensions.h \ tools/arguments.h \ utils.h -if !HAVE_IFADDRS_H -noinst_HEADERS += ../include/ifaddrs.h -endif - if IS_BIONIC noinst_HEADERS += ../include/lxcmntent.h \ ../include/openpty.h @@ -103,6 +100,7 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \ execute.c \ freezer.c \ file_utils.c file_utils.h \ + ../include/netns_ifaddrs.c ../include/netns_ifaddrs.h \ initutils.c initutils.h \ list.h \ log.c log.h \ @@ -139,10 +137,6 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \ version.h \ $(LSM_SOURCES) -if !HAVE_IFADDRS_H -liblxc_la_SOURCES += ../include/ifaddrs.c ../include/ifaddrs.h -endif - if IS_BIONIC liblxc_la_SOURCES += ../include/lxcmntent.c ../include/lxcmntent.h \ ../include/openpty.c ../include/openpty.h diff --git a/src/lxc/macro.h b/src/lxc/macro.h index 52acfee807..c9b46bd213 100644 --- a/src/lxc/macro.h +++ b/src/lxc/macro.h @@ -272,10 +272,20 @@ extern int __build_bug_on_failed; #define IFLA_NEW_NETNSID 45 #endif -#ifndef IFLA_IF_NETNSID +#ifdef IFLA_IF_NETNSID +#ifndef IFLA_TARGET_NETNSID +#define IFLA_TARGET_NETNSID = IFLA_IF_NETNSID +#endif +#else #define IFLA_IF_NETNSID 46 +#define IFLA_TARGET_NETNSID 46 +#endif + +#ifndef IFA_TARGET_NETNSID +#define IFA_TARGET_NETNSID 10 #endif + #ifndef RTM_NEWNSID #define RTM_NEWNSID 88 #endif @@ -304,6 +314,16 @@ extern int __build_bug_on_failed; #define MACVLAN_MODE_PASSTHRU 8 #endif +/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */ +enum { + __LXC_NETNSA_NONE, +#define __LXC_NETNSA_NSID_NOT_ASSIGNED -1 + __LXC_NETNSA_NSID, + __LXC_NETNSA_PID, + __LXC_NETNSA_FD, + __LXC_NETNSA_MAX, +}; + /* Length of abstract unix domain socket socket address. */ #define LXC_AUDS_ADDR_LEN sizeof(((struct sockaddr_un *)0)->sun_path) diff --git a/src/lxc/network.c b/src/lxc/network.c index 789d2a9296..8bfe6a1a2f 100644 --- a/src/lxc/network.c +++ b/src/lxc/network.c @@ -3181,35 +3181,6 @@ void lxc_delete_network(struct lxc_handler *handler) DEBUG("Deleted network devices"); } -int addattr(struct nlmsghdr *n, size_t maxlen, int type, const void *data, size_t alen) -{ - int len = RTA_LENGTH(alen); - struct rtattr *rta; - - errno = EMSGSIZE; - if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) - return -1; - - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; - if (alen) - memcpy(RTA_DATA(rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); - - return 0; -} - -/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */ -enum { - __LXC_NETNSA_NONE, -#define __LXC_NETNSA_NSID_NOT_ASSIGNED -1 - __LXC_NETNSA_NSID, - __LXC_NETNSA_PID, - __LXC_NETNSA_FD, - __LXC_NETNSA_MAX, -}; - int lxc_netns_set_nsid(int fd) { int ret; diff --git a/src/lxc/nl.c b/src/lxc/nl.c index bf2452f0e3..06a72fb88b 100644 --- a/src/lxc/nl.c +++ b/src/lxc/nl.c @@ -345,3 +345,22 @@ extern int netlink_close(struct nl_handler *handler) return 0; } +int addattr(struct nlmsghdr *n, size_t maxlen, int type, const void *data, + size_t alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + errno = EMSGSIZE; + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) + return -1; + + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + if (alen) + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + + return 0; +} diff --git a/src/lxc/nl.h b/src/lxc/nl.h index a00fc16df3..2afda5f0f0 100644 --- a/src/lxc/nl.h +++ b/src/lxc/nl.h @@ -23,6 +23,8 @@ #ifndef __LXC_NL_H #define __LXC_NL_H +#include + /* * Use this as a good size to allocate generic netlink messages */ @@ -259,5 +261,7 @@ void nlmsg_free(struct nlmsg *nlmsg); */ void *nlmsg_data(struct nlmsg *nlmsg); +extern int addattr(struct nlmsghdr *n, size_t maxlen, int type, + const void *data, size_t alen); #endif