diff mbox series

[iproute2,v7,1/2] lib/libnetlink: Add functions rtnl_talk_msg and rtnl_talk_iov

Message ID 20180109065908.19754-2-chrism@mellanox.com
State Changes Requested, archived
Delegated to: David Ahern
Headers show
Series tc: Add batchsize feature to batch mode | expand

Commit Message

Chris Mi Jan. 9, 2018, 6:59 a.m. UTC
rtnl_talk can only send a single message to kernel. Add two functions
rtnl_talk_msg and rtnl_talk_iov that can send multiple messages to kernel.
rtnl_talk_msg takes struct msghdr * as argument.
rtnl_talk_iov takes struct iovec * and iovlen as arguments.

Signed-off-by: Chris Mi <chrism@mellanox.com>
---
 include/libnetlink.h |  6 ++++
 lib/libnetlink.c     | 84 ++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 71 insertions(+), 19 deletions(-)

Comments

Phil Sutter Jan. 9, 2018, 7:24 p.m. UTC | #1
Hi,

On Tue, Jan 09, 2018 at 03:59:07PM +0900, Chris Mi wrote:
[...]
> diff --git a/lib/libnetlink.c b/lib/libnetlink.c
> index 00e6ce0c..ae0059f9 100644
> --- a/lib/libnetlink.c
> +++ b/lib/libnetlink.c
> @@ -581,39 +581,43 @@ static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
>  		strerror(-err->error));
>  }
>  
> -static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
> -		       struct nlmsghdr **answer,
> -		       bool show_rtnl_err, nl_ext_ack_fn_t errfn)
> +static int __rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
> +			   struct nlmsghdr **answer,
> +			   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 iovec iov = {
> -		.iov_base = n,
> -		.iov_len = n->nlmsg_len
> -	};
> +	int i, status, iovlen = m->msg_iovlen;
> +	struct iovec iov;
>  	struct msghdr msg = {
>  		.msg_name = &nladdr,
>  		.msg_namelen = sizeof(nladdr),
>  		.msg_iov = &iov,
>  		.msg_iovlen = 1,
>  	};
> -	char *buf;
> -
> -	n->nlmsg_seq = seq = ++rtnl->seq;
> +	unsigned int seq = 0;
> +	struct nlmsghdr *h;
>  
> -	if (answer == NULL)
> -		n->nlmsg_flags |= NLM_F_ACK;
> +	for (i = 0; i < iovlen; i++) {
> +		struct iovec *v;
> +		v = &m->msg_iov[i];
> +		h = v->iov_base;
> +		h->nlmsg_seq = seq = ++rtnl->seq;
> +		if (answer == NULL)
> +			h->nlmsg_flags |= NLM_F_ACK;
> +	}
>  
> -	status = sendmsg(rtnl->fd, &msg, 0);
> +	status = sendmsg(rtnl->fd, m, 0);
>  	if (status < 0) {
>  		perror("Cannot talk to rtnetlink");
>  		return -1;
>  	}
>  
> +	i = 0;
>  	while (1) {

for (i = 1; ; i++) ?

> +		char *buf;

Why did you move this declaration?

> +next:

Drop this and use 'continue' instead of 'goto next' below?

>  		status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
> +		++i;
>  
>  		if (status < 0)
>  			return status;
> @@ -642,7 +646,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
>  
>  			if (nladdr.nl_pid != 0 ||
>  			    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. */
>  				status -= NLMSG_ALIGN(len);
>  				h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
> @@ -662,7 +666,10 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
>  						*answer = (struct nlmsghdr *)buf;
>  					else
>  						free(buf);
> -					return 0;
> +					if (h->nlmsg_seq == seq)
> +						return 0;
> +					else
> +						goto next;
>  				}
>  
>  				if (rtnl->proto != NETLINK_SOCK_DIAG &&

Cheers, Phil
Chris Mi Jan. 10, 2018, 3 a.m. UTC | #2
> -----Original Message-----
> From: n0-1@orbyte.nwl.cc [mailto:n0-1@orbyte.nwl.cc] On Behalf Of Phil
> Sutter
> Sent: Wednesday, January 10, 2018 3:24 AM
> To: Chris Mi <chrism@mellanox.com>
> Cc: netdev@vger.kernel.org; gerlitz.or@gmail.com;
> stephen@networkplumber.org; dsahern@gmail.com;
> marcelo.leitner@gmail.com
> Subject: Re: [patch iproute2 v7 1/2] lib/libnetlink: Add functions
> rtnl_talk_msg and rtnl_talk_iov
> 
> Hi,
> 
> On Tue, Jan 09, 2018 at 03:59:07PM +0900, Chris Mi wrote:
> [...]
> > diff --git a/lib/libnetlink.c b/lib/libnetlink.c index
> > 00e6ce0c..ae0059f9 100644
> > --- a/lib/libnetlink.c
> > +++ b/lib/libnetlink.c
> > @@ -581,39 +581,43 @@ static void rtnl_talk_error(struct nlmsghdr *h,
> struct nlmsgerr *err,
> >  		strerror(-err->error));
> >  }
> >
> > -static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
> > -		       struct nlmsghdr **answer,
> > -		       bool show_rtnl_err, nl_ext_ack_fn_t errfn)
> > +static int __rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
> > +			   struct nlmsghdr **answer,
> > +			   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 iovec iov = {
> > -		.iov_base = n,
> > -		.iov_len = n->nlmsg_len
> > -	};
> > +	int i, status, iovlen = m->msg_iovlen;
> > +	struct iovec iov;
> >  	struct msghdr msg = {
> >  		.msg_name = &nladdr,
> >  		.msg_namelen = sizeof(nladdr),
> >  		.msg_iov = &iov,
> >  		.msg_iovlen = 1,
> >  	};
> > -	char *buf;
> > -
> > -	n->nlmsg_seq = seq = ++rtnl->seq;
> > +	unsigned int seq = 0;
> > +	struct nlmsghdr *h;
> >
> > -	if (answer == NULL)
> > -		n->nlmsg_flags |= NLM_F_ACK;
> > +	for (i = 0; i < iovlen; i++) {
> > +		struct iovec *v;
> > +		v = &m->msg_iov[i];
> > +		h = v->iov_base;
> > +		h->nlmsg_seq = seq = ++rtnl->seq;
> > +		if (answer == NULL)
> > +			h->nlmsg_flags |= NLM_F_ACK;
> > +	}
> >
> > -	status = sendmsg(rtnl->fd, &msg, 0);
> > +	status = sendmsg(rtnl->fd, m, 0);
> >  	if (status < 0) {
> >  		perror("Cannot talk to rtnetlink");
> >  		return -1;
> >  	}
> >
> > +	i = 0;
> >  	while (1) {
> 
> for (i = 1; ; i++) ?
> 
> > +		char *buf;
> 
> Why did you move this declaration?
> 
> > +next:
> 
> Drop this and use 'continue' instead of 'goto next' below?
Actually there are two loops, I need go to the outer while loop instead of the inner for loop.
> 
> >  		status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
> > +		++i;
> >
> >  		if (status < 0)
> >  			return status;
> > @@ -642,7 +646,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl,
> > struct nlmsghdr *n,
> >
> >  			if (nladdr.nl_pid != 0 ||
> >  			    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. */
> >  				status -= NLMSG_ALIGN(len);
> >  				h = (struct nlmsghdr *)((char *)h +
> NLMSG_ALIGN(len)); @@ -662,7
> > +666,10 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr
> *n,
> >  						*answer = (struct nlmsghdr
> *)buf;
> >  					else
> >  						free(buf);
> > -					return 0;
> > +					if (h->nlmsg_seq == seq)
> > +						return 0;
> > +					else
> > +						goto next;
> >  				}
> >
> >  				if (rtnl->proto != NETLINK_SOCK_DIAG &&
> 
> Cheers, Phil
Phil Sutter Jan. 10, 2018, 11:01 a.m. UTC | #3
Hi Chris,

On Wed, Jan 10, 2018 at 03:00:23AM +0000, Chris Mi wrote:
[...]
> > Drop this and use 'continue' instead of 'goto next' below?
> Actually there are two loops, I need go to the outer while loop instead of the inner for loop.

Oh, I missed that. Sorry for the noise!

Cheers, Phil
diff mbox series

Patch

diff --git a/include/libnetlink.h b/include/libnetlink.h
index a4d83b9e..e9a63dbc 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -96,6 +96,12 @@  int rtnl_dump_filter_nc(struct rtnl_handle *rth,
 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 	      struct nlmsghdr **answer)
 	__attribute__((warn_unused_result));
+int rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+		  struct nlmsghdr **answer)
+	__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,
 	      struct nlmsghdr **answer, nl_ext_ack_fn_t errfn)
 	__attribute__((warn_unused_result));
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 00e6ce0c..ae0059f9 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -581,39 +581,43 @@  static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
 		strerror(-err->error));
 }
 
-static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
-		       struct nlmsghdr **answer,
-		       bool show_rtnl_err, nl_ext_ack_fn_t errfn)
+static int __rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+			   struct nlmsghdr **answer,
+			   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 iovec iov = {
-		.iov_base = n,
-		.iov_len = n->nlmsg_len
-	};
+	int i, status, iovlen = m->msg_iovlen;
+	struct iovec iov;
 	struct msghdr msg = {
 		.msg_name = &nladdr,
 		.msg_namelen = sizeof(nladdr),
 		.msg_iov = &iov,
 		.msg_iovlen = 1,
 	};
-	char *buf;
-
-	n->nlmsg_seq = seq = ++rtnl->seq;
+	unsigned int seq = 0;
+	struct nlmsghdr *h;
 
-	if (answer == NULL)
-		n->nlmsg_flags |= NLM_F_ACK;
+	for (i = 0; i < iovlen; i++) {
+		struct iovec *v;
+		v = &m->msg_iov[i];
+		h = v->iov_base;
+		h->nlmsg_seq = seq = ++rtnl->seq;
+		if (answer == NULL)
+			h->nlmsg_flags |= NLM_F_ACK;
+	}
 
-	status = sendmsg(rtnl->fd, &msg, 0);
+	status = sendmsg(rtnl->fd, m, 0);
 	if (status < 0) {
 		perror("Cannot talk to rtnetlink");
 		return -1;
 	}
 
+	i = 0;
 	while (1) {
+		char *buf;
+next:
 		status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
+		++i;
 
 		if (status < 0)
 			return status;
@@ -642,7 +646,7 @@  static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 
 			if (nladdr.nl_pid != 0 ||
 			    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. */
 				status -= NLMSG_ALIGN(len);
 				h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
@@ -662,7 +666,10 @@  static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 						*answer = (struct nlmsghdr *)buf;
 					else
 						free(buf);
-					return 0;
+					if (h->nlmsg_seq == seq)
+						return 0;
+					else
+						goto next;
 				}
 
 				if (rtnl->proto != NETLINK_SOCK_DIAG &&
@@ -671,7 +678,7 @@  static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 
 				errno = -err->error;
 				free(buf);
-				return -1;
+				return -i;
 			}
 
 			if (answer) {
@@ -698,12 +705,51 @@  static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 	}
 }
 
+static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *msg_iov,
+			   size_t iovlen, struct nlmsghdr **answer,
+			   bool show_rtnl_err, nl_ext_ack_fn_t errfn)
+{
+	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
+	struct msghdr msg = {
+		.msg_name = &nladdr,
+		.msg_namelen = sizeof(nladdr),
+		.msg_iov = msg_iov,
+		.msg_iovlen = iovlen,
+	};
+
+	return __rtnl_talk_msg(rtnl, &msg, answer, show_rtnl_err, errfn);
+}
+
+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,
 	      struct nlmsghdr **answer)
 {
 	return __rtnl_talk(rtnl, n, answer, true, NULL);
 }
 
+int rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+		  struct nlmsghdr **answer)
+{
+	return __rtnl_talk_msg(rtnl, m, 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,
 		     struct nlmsghdr **answer,
 		     nl_ext_ack_fn_t errfn)