diff --git a/ip/iplink.c b/ip/iplink.c
index 5ec33a98b96e..422e2fdccde5 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -135,14 +135,6 @@ static void usage(void)
 	iplink_usage();
 }
 
-static int on_off(const char *msg, const char *realval)
-{
-	fprintf(stderr,
-		"Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n",
-		msg, realval);
-	return -1;
-}
-
 static void *BODY;		/* cached dlopen(NULL) handle */
 static struct link_util *linkutil_list;
 
@@ -351,6 +343,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
 	int len, argc = *argcp;
 	char **argv = *argvp;
 	struct rtattr *vfinfo;
+	int ret;
 
 	tivt.min_tx_rate = -1;
 	tivt.max_tx_rate = -1;
@@ -463,12 +456,9 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
 			struct ifla_vf_spoofchk ivs;
 
 			NEXT_ARG();
-			if (matches(*argv, "on") == 0)
-				ivs.setting = 1;
-			else if (matches(*argv, "off") == 0)
-				ivs.setting = 0;
-			else
-				return on_off("spoofchk", *argv);
+			ivs.setting = parse_on_off("spoofchk", *argv, &ret);
+			if (ret)
+				return ret;
 			ivs.vf = vf;
 			addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK,
 				  &ivs, sizeof(ivs));
@@ -477,12 +467,9 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
 			struct ifla_vf_rss_query_en ivs;
 
 			NEXT_ARG();
-			if (matches(*argv, "on") == 0)
-				ivs.setting = 1;
-			else if (matches(*argv, "off") == 0)
-				ivs.setting = 0;
-			else
-				return on_off("query_rss", *argv);
+			ivs.setting = parse_on_off("query_rss", *argv, &ret);
+			if (ret)
+				return ret;
 			ivs.vf = vf;
 			addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN,
 				  &ivs, sizeof(ivs));
@@ -491,12 +478,9 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
 			struct ifla_vf_trust ivt;
 
 			NEXT_ARG();
-			if (matches(*argv, "on") == 0)
-				ivt.setting = 1;
-			else if (matches(*argv, "off") == 0)
-				ivt.setting = 0;
-			else
-				invarg("Invalid \"trust\" value\n", *argv);
+			ivt.setting = parse_on_off("trust", *argv, &ret);
+			if (ret)
+				return ret;
 			ivt.vf = vf;
 			addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST,
 				  &ivt, sizeof(ivt));
@@ -594,6 +578,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
 	int index = 0;
 	int group = -1;
 	int addr_len = 0;
+	int err;
 
 	ret = argc;
 
@@ -687,62 +672,53 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
 			NEXT_ARG();
 			req->i.ifi_change |= IFF_MULTICAST;
 
-			if (strcmp(*argv, "on") == 0)
-				req->i.ifi_flags |= IFF_MULTICAST;
-			else if (strcmp(*argv, "off") == 0)
-				req->i.ifi_flags &= ~IFF_MULTICAST;
-			else
-				return on_off("multicast", *argv);
+			parse_flag_on_off("multicast", *argv, &req->i.ifi_flags,
+					  IFF_MULTICAST, &err);
+			if (err)
+				return err;
 		} else if (strcmp(*argv, "allmulticast") == 0) {
 			NEXT_ARG();
 			req->i.ifi_change |= IFF_ALLMULTI;
 
-			if (strcmp(*argv, "on") == 0)
-				req->i.ifi_flags |= IFF_ALLMULTI;
-			else if (strcmp(*argv, "off") == 0)
-				req->i.ifi_flags &= ~IFF_ALLMULTI;
-			else
-				return on_off("allmulticast", *argv);
+			parse_flag_on_off("allmulticast", *argv, &req->i.ifi_flags,
+					  IFF_ALLMULTI, &err);
+			if (err)
+				return err;
 		} else if (strcmp(*argv, "promisc") == 0) {
 			NEXT_ARG();
 			req->i.ifi_change |= IFF_PROMISC;
 
-			if (strcmp(*argv, "on") == 0)
-				req->i.ifi_flags |= IFF_PROMISC;
-			else if (strcmp(*argv, "off") == 0)
-				req->i.ifi_flags &= ~IFF_PROMISC;
-			else
-				return on_off("promisc", *argv);
+			parse_flag_on_off("promisc", *argv, &req->i.ifi_flags,
+					  IFF_PROMISC, &err);
+			if (err)
+				return err;
 		} else if (strcmp(*argv, "trailers") == 0) {
+			int on_off;
+
 			NEXT_ARG();
 			req->i.ifi_change |= IFF_NOTRAILERS;
 
-			if (strcmp(*argv, "off") == 0)
-				req->i.ifi_flags |= IFF_NOTRAILERS;
-			else if (strcmp(*argv, "on") == 0)
-				req->i.ifi_flags &= ~IFF_NOTRAILERS;
-			else
-				return on_off("trailers", *argv);
+			on_off = parse_on_off("trailers", *argv, &err);
+			if (err)
+				return err;
+			set_flag(&req->i.ifi_flags, IFF_NOTRAILERS, !on_off);
 		} else if (strcmp(*argv, "arp") == 0) {
+			int on_off;
+
 			NEXT_ARG();
 			req->i.ifi_change |= IFF_NOARP;
 
-			if (strcmp(*argv, "on") == 0)
-				req->i.ifi_flags &= ~IFF_NOARP;
-			else if (strcmp(*argv, "off") == 0)
-				req->i.ifi_flags |= IFF_NOARP;
-			else
-				return on_off("arp", *argv);
+			on_off = parse_on_off("arp", *argv, &err);
+			if (err)
+				return err;
+			set_flag(&req->i.ifi_flags, IFF_NOARP, !on_off);
 		} else if (strcmp(*argv, "carrier") == 0) {
 			int carrier;
 
 			NEXT_ARG();
-			if (strcmp(*argv, "on") == 0)
-				carrier = 1;
-			else if (strcmp(*argv, "off") == 0)
-				carrier = 0;
-			else
-				return on_off("carrier", *argv);
+			carrier = parse_on_off("carrier", *argv, &err);
+			if (err)
+				return err;
 
 			addattr8(&req->n, sizeof(*req), IFLA_CARRIER, carrier);
 		} else if (strcmp(*argv, "vf") == 0) {
@@ -793,12 +769,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
 			NEXT_ARG();
 			req->i.ifi_change |= IFF_DYNAMIC;
 
-			if (strcmp(*argv, "on") == 0)
-				req->i.ifi_flags |= IFF_DYNAMIC;
-			else if (strcmp(*argv, "off") == 0)
-				req->i.ifi_flags &= ~IFF_DYNAMIC;
-			else
-				return on_off("dynamic", *argv);
+			parse_flag_on_off("dynamic", *argv, &req->i.ifi_flags,
+					  IFF_DYNAMIC, &err);
+			if (err)
+				return err;
 		} else if (matches(*argv, "type") == 0) {
 			NEXT_ARG();
 			*type = *argv;
@@ -895,12 +869,9 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
 			unsigned int proto_down;
 
 			NEXT_ARG();
-			if (strcmp(*argv, "on") == 0)
-				proto_down = 1;
-			else if (strcmp(*argv, "off") == 0)
-				proto_down = 0;
-			else
-				return on_off("protodown", *argv);
+			proto_down = parse_on_off("protodown", *argv, &err);
+			if (err)
+				return err;
 			addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
 				 proto_down);
 		} else if (strcmp(*argv, "gso_max_size") == 0) {
@@ -1320,6 +1291,7 @@ static int do_set(int argc, char **argv)
 	struct ifreq ifr0, ifr1;
 	char *newname = NULL;
 	int htype, halen;
+	int ret;
 
 	while (argc > 0) {
 		if (strcmp(*argv, "up") == 0) {
@@ -1357,63 +1329,41 @@ static int do_set(int argc, char **argv)
 		} else if (strcmp(*argv, "multicast") == 0) {
 			NEXT_ARG();
 			mask |= IFF_MULTICAST;
-
-			if (strcmp(*argv, "on") == 0)
-				flags |= IFF_MULTICAST;
-			else if (strcmp(*argv, "off") == 0)
-				flags &= ~IFF_MULTICAST;
-			else
-				return on_off("multicast", *argv);
+			parse_flag_on_off("multicast", *argv, &flags, IFF_MULTICAST, &ret);
+			if (ret)
+				return ret;
 		} else if (strcmp(*argv, "allmulticast") == 0) {
 			NEXT_ARG();
 			mask |= IFF_ALLMULTI;
-
-			if (strcmp(*argv, "on") == 0)
-				flags |= IFF_ALLMULTI;
-			else if (strcmp(*argv, "off") == 0)
-				flags &= ~IFF_ALLMULTI;
-			else
-				return on_off("allmulticast", *argv);
+			parse_flag_on_off("allmulticast", *argv, &flags, IFF_ALLMULTI, &ret);
 		} else if (strcmp(*argv, "promisc") == 0) {
 			NEXT_ARG();
 			mask |= IFF_PROMISC;
-
-			if (strcmp(*argv, "on") == 0)
-				flags |= IFF_PROMISC;
-			else if (strcmp(*argv, "off") == 0)
-				flags &= ~IFF_PROMISC;
-			else
-				return on_off("promisc", *argv);
+			parse_flag_on_off("promisc", *argv, &flags, IFF_PROMISC, &ret);
 		} else if (strcmp(*argv, "trailers") == 0) {
+			int on_off;
+
 			NEXT_ARG();
 			mask |= IFF_NOTRAILERS;
-
-			if (strcmp(*argv, "off") == 0)
-				flags |= IFF_NOTRAILERS;
-			else if (strcmp(*argv, "on") == 0)
-				flags &= ~IFF_NOTRAILERS;
-			else
-				return on_off("trailers", *argv);
+			on_off = parse_on_off("trailers", *argv, &ret);
+			if (ret)
+				return ret;
+			set_flag(&flags, IFF_NOTRAILERS, !on_off);
 		} else if (strcmp(*argv, "arp") == 0) {
+			int on_off;
+
 			NEXT_ARG();
 			mask |= IFF_NOARP;
-
-			if (strcmp(*argv, "on") == 0)
-				flags &= ~IFF_NOARP;
-			else if (strcmp(*argv, "off") == 0)
-				flags |= IFF_NOARP;
-			else
-				return on_off("arp", *argv);
+			on_off = parse_on_off("arp", *argv, &ret);
+			if (ret)
+				return ret;
+			set_flag(&flags, IFF_NOARP, !on_off);
 		} else if (matches(*argv, "dynamic") == 0) {
 			NEXT_ARG();
 			mask |= IFF_DYNAMIC;
-
-			if (strcmp(*argv, "on") == 0)
-				flags |= IFF_DYNAMIC;
-			else if (strcmp(*argv, "off") == 0)
-				flags &= ~IFF_DYNAMIC;
-			else
-				return on_off("dynamic", *argv);
+			parse_flag_on_off("dynamic", *argv, &flags, IFF_DYNAMIC, &ret);
+			if (ret)
+				return ret;
 		} else {
 			if (strcmp(*argv, "dev") == 0)
 				NEXT_ARG();
