ip: allow set and display of link mode parameter

The kernel supports a link mode attribute (which can be dormant or default).
This attribute is used to control how the link watch engine
handles operstate transistion.

This adds a new parameter to ip link command to allow setting and
displaying the value.
---
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 8123da1..aea1a81 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -158,6 +158,20 @@
 		fprintf(f, "qlen %d", qlen);
 }
 
+static const char *link_modes[] = {
+	"DEFAULT", "DORMANT"
+};
+
+static void print_linkmode(FILE *f, struct rtattr *tb)
+{
+	unsigned int mode = rta_getattr_u8(tb);
+
+	if (mode >= sizeof(link_modes) / sizeof(link_modes[0]))
+		fprintf(f, "mode %d ", mode);
+	else
+		fprintf(f, "mode %s ", link_modes[mode]);
+}
+
 static void print_linktype(FILE *fp, struct rtattr *tb)
 {
 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
@@ -398,9 +412,13 @@
 		SPRINT_BUF(b1);
 		fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
 	}
+
 	if (tb[IFLA_OPERSTATE])
 		print_operstate(fp, *(__u8 *)RTA_DATA(tb[IFLA_OPERSTATE]));
-		
+
+	if (do_link && tb[IFLA_LINKMODE])
+		print_linkmode(fp, tb[IFLA_LINKMODE]);
+
 	if (filter.showqueue)
 		print_queuelen(fp, tb);
 
diff --git a/ip/iplink.c b/ip/iplink.c
index 8481514..814a92c 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -132,6 +132,15 @@
 	return l;
 }
 
+int get_link_mode(const char *mode)
+{
+	if (strcmp(mode, "default") == 0)
+		return IF_LINK_MODE_DEFAULT;
+	if (strcmp(mode, "dormant") == 0)
+		return IF_LINK_MODE_DORMANT;
+	return -1;
+}
+
 #if IPLINK_IOCTL_COMPAT
 static int have_rtnl_newlink = -1;
 
@@ -421,6 +430,13 @@
 				duparg("group", *argv);
 			if (rtnl_group_a2n(group, *argv))
 				invarg("Invalid \"group\" value\n", *argv);
+		} else if (strcmp(*argv, "mode") == 0) {
+			int mode;
+			NEXT_ARG();
+			mode  = get_link_mode(*argv);
+			if (mode < 0)
+				invarg("Invalid link mode\n", *argv);
+			addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
 		} else {
 			if (strcmp(*argv, "dev") == 0) {
 				NEXT_ARG();
diff --git a/man/man8/ip-link.8 b/man/man8/ip-link.8
index 8c63584..acc6d28 100644
--- a/man/man8/ip-link.8
+++ b/man/man8/ip-link.8
@@ -100,6 +100,9 @@
 .B spoofchk { on | off }
 ] |
 .br
+.B mode
+.IR LINKMODE " |"
+.br
 .B master
 .IR DEVICE
 .br
@@ -249,6 +252,14 @@
 .IR "NETNSNAME".
 
 .TP
+.BI mode " LINKMODE"
+allows setting link mode which determines which RFC2863 operational state
+the device will transistion to when it is brought up. Setting
+.I dormant
+mode changes the behaviour so that device goes into DORMANT state instead
+of UP when driver is ready.
+
+.TP
 .BI alias " NAME"
 give the device a symbolic name for easy reference.