lib/libnetlink: Add a new function rtnl_talk_iov

rtnl_talk can only send a single message to kernel. Add a new function
rtnl_talk_iov that can send multiple messages to kernel.
rtnl_talk_iov takes struct iovec * and iovlen as arguments.

Signed-off-by: Chris Mi <chrism@mellanox.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Chris Mi 2018-01-12 14:13:15 +09:00 committed by David Ahern
parent 6a21ca8a4a
commit 72a2ff3916
2 changed files with 49 additions and 19 deletions

View File

@ -96,6 +96,9 @@ int rtnl_dump_filter_nc(struct rtnl_handle *rth,
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer) struct nlmsghdr **answer)
__attribute__((warn_unused_result)); __attribute__((warn_unused_result));
int rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iovec, size_t iovlen,
struct nlmsghdr **answer)
__attribute__((warn_unused_result));
int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n, int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer, nl_ext_ack_fn_t errfn) struct nlmsghdr **answer, nl_ext_ack_fn_t errfn)
__attribute__((warn_unused_result)); __attribute__((warn_unused_result));

View File

@ -581,30 +581,30 @@ static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
strerror(-err->error)); strerror(-err->error));
} }
static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer, static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iov,
size_t iovlen, struct nlmsghdr **answer,
bool show_rtnl_err, nl_ext_ack_fn_t errfn) bool show_rtnl_err, nl_ext_ack_fn_t errfn)
{ {
int status;
unsigned int seq;
struct nlmsghdr *h;
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
struct iovec iov = { struct iovec riov;
.iov_base = n,
.iov_len = n->nlmsg_len
};
struct msghdr msg = { struct msghdr msg = {
.msg_name = &nladdr, .msg_name = &nladdr,
.msg_namelen = sizeof(nladdr), .msg_namelen = sizeof(nladdr),
.msg_iov = &iov, .msg_iov = iov,
.msg_iovlen = 1, .msg_iovlen = iovlen,
}; };
unsigned int seq = 0;
struct nlmsghdr *h;
int i, status;
char *buf; char *buf;
n->nlmsg_seq = seq = ++rtnl->seq; for (i = 0; i < iovlen; i++) {
h = iov[i].iov_base;
h->nlmsg_seq = seq = ++rtnl->seq;
if (answer == NULL) if (answer == NULL)
n->nlmsg_flags |= NLM_F_ACK; h->nlmsg_flags |= NLM_F_ACK;
}
status = sendmsg(rtnl->fd, &msg, 0); status = sendmsg(rtnl->fd, &msg, 0);
if (status < 0) { if (status < 0) {
@ -612,8 +612,14 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
return -1; return -1;
} }
/* change msg to use the response iov */
msg.msg_iov = &riov;
msg.msg_iovlen = 1;
i = 0;
while (1) { while (1) {
next:
status = rtnl_recvmsg(rtnl->fd, &msg, &buf); status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
++i;
if (status < 0) if (status < 0)
return status; return status;
@ -642,7 +648,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
if (nladdr.nl_pid != 0 || if (nladdr.nl_pid != 0 ||
h->nlmsg_pid != rtnl->local.nl_pid || h->nlmsg_pid != rtnl->local.nl_pid ||
h->nlmsg_seq != seq) { h->nlmsg_seq > seq || h->nlmsg_seq < seq - iovlen) {
/* Don't forget to skip that message. */ /* Don't forget to skip that message. */
status -= NLMSG_ALIGN(len); status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
@ -662,7 +668,10 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
*answer = (struct nlmsghdr *)buf; *answer = (struct nlmsghdr *)buf;
else else
free(buf); free(buf);
if (h->nlmsg_seq == seq)
return 0; return 0;
else
goto next;
} }
if (rtnl->proto != NETLINK_SOCK_DIAG && if (rtnl->proto != NETLINK_SOCK_DIAG &&
@ -671,7 +680,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
errno = -err->error; errno = -err->error;
free(buf); free(buf);
return -1; return -i;
} }
if (answer) { if (answer) {
@ -698,12 +707,30 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
} }
} }
static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer,
bool show_rtnl_err, nl_ext_ack_fn_t errfn)
{
struct iovec iov = {
.iov_base = n,
.iov_len = n->nlmsg_len
};
return __rtnl_talk_iov(rtnl, &iov, 1, answer, show_rtnl_err, errfn);
}
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer) struct nlmsghdr **answer)
{ {
return __rtnl_talk(rtnl, n, answer, true, NULL); return __rtnl_talk(rtnl, n, answer, true, NULL);
} }
int rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iovec, size_t iovlen,
struct nlmsghdr **answer)
{
return __rtnl_talk_iov(rtnl, iovec, iovlen, answer, true, NULL);
}
int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n, int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer, struct nlmsghdr **answer,
nl_ext_ack_fn_t errfn) nl_ext_ack_fn_t errfn)