netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* New "ip wait" subcommand for iproute2
@ 2015-12-28 23:47 Nathaniel W Filardo
  2015-12-30 20:31 ` Stephen Hemminger
  0 siblings, 1 reply; 2+ messages in thread
From: Nathaniel W Filardo @ 2015-12-28 23:47 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: text/plain, Size: 6913 bytes --]

Hallo netdev@,

I had occasion to want to programmatically wait for an interface to become
available from within a shell script, but found there to be no off-the-shelf
tool for such a thing.  Could this patch be considered for inclusion as part
of iproute2?  It adds an "ip wait link" subcommand ("link" required in case
someone wants to add things like "ip wait addr" or somesuch) based quite
heavily on the ipmonitor.c file.

For example, one might "ip wait link dev eth0 up" to wait for an interface
of that name to appear (specifically, for a RTM_NEWLINK message).  "ip wait
link dev eth0 down" will wait for it to go away (RTM_DELLINK).

This should be checkpatch clean, but please let me know if I missed
something.

Cheers,
--nwf;

From f6e0acbc07af9650cb5e66c0dec08e6e3e878f79 Mon Sep 17 00:00:00 2001
From: Nathaniel Wesley Filardo <nwf@cs.jhu.edu>
Date: Mon, 28 Dec 2015 18:35:17 -0500
Subject: [PATCH] New 'ip wait' command

Signed-off-by: Nathaniel Filardo <nwf@cs.jhu.edu>
---
 ip/Makefile    |   2 +-
 ip/ip.c        |   3 +-
 ip/ip_common.h |   1 +
 ip/ipwait.c    | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 153 insertions(+), 2 deletions(-)
 create mode 100644 ip/ipwait.c

diff --git a/ip/Makefile b/ip/Makefile
index f3d2987..cf12af7 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -7,7 +7,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
     iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \
     link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
     iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
-    iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o
+    iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipwait.o
 
 RTMONOBJ=rtmon.o
 
diff --git a/ip/ip.c b/ip/ip.c
index eea00b8..36d8a24 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -51,7 +51,7 @@ static void usage(void)
 "       ip [ -force ] -batch filename\n"
 "where  OBJECT := { link | address | addrlabel | route | rule | neighbor | ntable |\n"
 "                   tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n"
-"                   netns | l2tp | fou | tcp_metrics | token | netconf }\n"
+"                   netns | l2tp | fou | tcp_metrics | token | netconf | wait }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
 "                    -h[uman-readable] | -iec |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
@@ -97,6 +97,7 @@ static const struct cmd {
 	{ "mrule",	do_multirule },
 	{ "netns",	do_netns },
 	{ "netconf",	do_ipnetconf },
+	{ "wait",	do_ipwait },
 	{ "help",	do_help },
 	{ 0 }
 };
diff --git a/ip/ip_common.h b/ip/ip_common.h
index 9a846df..5670b9b 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -54,6 +54,7 @@ int do_ipfou(int argc, char **argv);
 int do_tcp_metrics(int argc, char **argv);
 int do_ipnetconf(int argc, char **argv);
 int do_iptoken(int argc, char **argv);
+int do_ipwait(int argc, char **argv);
 int iplink_get(unsigned int flags, char *name, __u32 filt_mask);
 
 static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
diff --git a/ip/ipwait.c b/ip/ipwait.c
new file mode 100644
index 0000000..998fb21
--- /dev/null
+++ b/ip/ipwait.c
@@ -0,0 +1,149 @@
+/*
+ * ipwait.c		"ip wait".
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> (ipmonitor.c)
+ *          Nathaniel Filardo <nwf@cs.jhu.edu> (this file)
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <time.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+static void usage(void) __attribute__((noreturn));
+int listen_all_nsid;
+int wait_for;
+char *wait_dev;
+int verbose;
+
+static void usage(void)
+{
+	fprintf(stderr,
+		"Usage: ip wait [all-nsid] [verbose] link dev DEVICE {up | down}");
+	exit(-1);
+}
+
+static int accept_msg(const struct sockaddr_nl *who,
+		      struct rtnl_ctrl_data *ctrl,
+		      struct nlmsghdr *n, void *arg)
+{
+	int done = 0;
+
+	if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
+		if (wait_for == n->nlmsg_type
+		    && wait_for == RTM_DELLINK
+		    && ll_name_to_index(wait_dev) != 0)
+			done = 1;
+
+		ll_remember_index(who, n, NULL);
+		if (verbose)
+			print_linkinfo(who, n, stdout);
+
+		if (wait_for == n->nlmsg_type
+		    && wait_for == RTM_NEWLINK
+		    && ll_name_to_index(wait_dev) != 0)
+			done = 1;
+	}
+	if (done) {
+		fflush(stdout);
+		exit(0);
+	}
+	return 0;
+}
+
+int do_ipwait(int argc, char **argv)
+{
+	unsigned groups = 0;
+	int llink = 0;
+	int wait_up = 0;
+	int wait_down = 0;
+
+	rtnl_close(&rth);
+
+	while (argc > 0) {
+		if (matches(*argv, "all-nsid") == 0) {
+			listen_all_nsid = 1;
+		} else if (matches(*argv, "verbose") == 0) {
+			verbose = 1;
+		} else if (matches(*argv, "link") == 0) {
+			llink = 1;
+		} else if (matches(*argv, "up") == 0) {
+			wait_up = 1;
+		} else if (matches(*argv, "down") == 0) {
+			wait_down = 1;
+		} else if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			wait_dev = *argv;
+		} else if (strcmp(*argv, "help") == 0) {
+			usage();
+		} else {
+			fprintf(stderr,
+				"Argument \"%s\" is unknown, try \"ip wait help\".\n",
+				*argv);
+			exit(-1);
+		}
+		argc--;	argv++;
+	}
+
+	if (!wait_down)
+		wait_for = RTM_NEWLINK;
+	else if (!wait_up && wait_down)
+		wait_for = RTM_DELLINK;
+	else if (wait_up && wait_down) {
+		fprintf(stderr, "Please specify one direction to wait...\n");
+		exit(-1);
+	}
+	if (llink != 1) {
+		fprintf(stderr, "Must specify link\n");
+		exit(-1);
+	}
+	if (wait_dev == NULL) {
+		fprintf(stderr, "Must specify device\n");
+		exit(-1);
+	}
+	{
+		int ifindex = ll_name_to_index(wait_dev);
+
+		if (wait_up && ifindex)
+			exit(0);
+		if (wait_down && !ifindex)
+			exit(0);
+
+		ipaddr_reset_filter(1, ifindex);
+		iproute_reset_filter(ifindex);
+		ipmroute_reset_filter(ifindex);
+		ipneigh_reset_filter(ifindex);
+		ipnetconf_reset_filter(ifindex);
+	}
+
+	if (llink)
+		groups |= nl_mgrp(RTNLGRP_LINK);
+
+	if (rtnl_open(&rth, groups) < 0)
+		exit(1);
+	if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
+		exit(1);
+
+	ll_init_map(&rth);
+	netns_map_init();
+
+	if (rtnl_listen(&rth, accept_msg, stdout) < 0)
+		exit(2);
+
+	return 0;
+}
-- 
2.6.4


[-- Attachment #2: Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: New "ip wait" subcommand for iproute2
  2015-12-28 23:47 New "ip wait" subcommand for iproute2 Nathaniel W Filardo
@ 2015-12-30 20:31 ` Stephen Hemminger
  0 siblings, 0 replies; 2+ messages in thread
From: Stephen Hemminger @ 2015-12-30 20:31 UTC (permalink / raw)
  To: Nathaniel W Filardo; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 1878 bytes --]

On Mon, 28 Dec 2015 18:47:51 -0500
Nathaniel W Filardo <nwf@cs.jhu.edu> wrote:

> Hallo netdev@,
> 
> I had occasion to want to programmatically wait for an interface to become
> available from within a shell script, but found there to be no off-the-shelf
> tool for such a thing.  Could this patch be considered for inclusion as part
> of iproute2?  It adds an "ip wait link" subcommand ("link" required in case
> someone wants to add things like "ip wait addr" or somesuch) based quite
> heavily on the ipmonitor.c file.
> 
> For example, one might "ip wait link dev eth0 up" to wait for an interface
> of that name to appear (specifically, for a RTM_NEWLINK message).  "ip wait
> link dev eth0 down" will wait for it to go away (RTM_DELLINK).
> 
> This should be checkpatch clean, but please let me know if I missed
> something.
> 
> Cheers,
> --nwf;
>


Thank you for your contribution, it looks useful.
Could you also update the man page?

> +static int accept_msg(const struct sockaddr_nl *who,
> +		      struct rtnl_ctrl_data *ctrl,
> +		      struct nlmsghdr *n, void *arg)
> +{
> +	int done = 0;
> +
> +	if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
> +		if (wait_for == n->nlmsg_type
> +		    && wait_for == RTM_DELLINK
> +		    && ll_name_to_index(wait_dev) != 0)
> +			done = 1;
> +
> +		ll_remember_index(who, n, NULL);
> +		if (verbose)
> +			print_linkinfo(who, n, stdout);
> +
> +		if (wait_for == n->nlmsg_type
> +		    && wait_for == RTM_NEWLINK
> +		    && ll_name_to_index(wait_dev) != 0)
> +			done = 1;
> +	}
> +	if (done) {
> +		fflush(stdout);
> +		exit(0);

I don't think you need explicit fflush here. Stdio does it automatically.
Which means all the conditional(done) can be removed.

Have you considered how wait could be used with --batch option
to write a script?



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-12-30 20:31 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-28 23:47 New "ip wait" subcommand for iproute2 Nathaniel W Filardo
2015-12-30 20:31 ` Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).