Merge branch 'master' into net-next
diff --git a/include/utils.h b/include/utils.h
index 27562a1..82f1aa7 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -248,5 +248,6 @@
 		bool show_label);
 
 char *int_to_str(int val, char *buf);
+int get_guid(__u64 *guid, const char *arg);
 
 #endif /* __UTILS_H__ */
diff --git a/ip/iplink.c b/ip/iplink.c
index f2a2e13..365240e 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -317,7 +317,8 @@
 					len, halen);
 				return -1;
 			}
-			addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
+			addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC,
+				  &ivm, sizeof(ivm));
 		} else if (matches(*argv, "vlan") == 0) {
 			struct ifla_vf_vlan ivv;
 
@@ -338,7 +339,8 @@
 					PREV_ARG();
 				}
 			}
-			addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
+			addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN,
+				  &ivv, sizeof(ivv));
 		} else if (matches(*argv, "rate") == 0) {
 			struct ifla_vf_tx_rate ivt;
 
@@ -378,7 +380,8 @@
 			else
 				return on_off("spoofchk", *argv);
 			ivs.vf = vf;
-			addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
+			addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK,
+				  &ivs, sizeof(ivs));
 
 		} else if (matches(*argv, "query_rss") == 0) {
 			struct ifla_vf_rss_query_en ivs;
@@ -391,7 +394,8 @@
 			else
 				return on_off("query_rss", *argv);
 			ivs.vf = vf;
-			addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs));
+			addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN,
+				  &ivs, sizeof(ivs));
 
 		} else if (matches(*argv, "trust") == 0) {
 			struct ifla_vf_trust ivt;
@@ -404,7 +408,8 @@
 			else
 				invarg("Invalid \"trust\" value\n", *argv);
 			ivt.vf = vf;
-			addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST, &ivt, sizeof(ivt));
+			addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST,
+				  &ivt, sizeof(ivt));
 
 		} else if (matches(*argv, "state") == 0) {
 			struct ifla_vf_link_state ivl;
@@ -419,7 +424,30 @@
 			else
 				invarg("Invalid \"state\" value\n", *argv);
 			ivl.vf = vf;
-			addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl));
+			addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE,
+				  &ivl, sizeof(ivl));
+		} else if (matches(*argv, "node_guid") == 0) {
+			struct ifla_vf_guid ivg;
+
+			NEXT_ARG();
+			ivg.vf = vf;
+			if (get_guid(&ivg.guid, *argv)) {
+				invarg("Invalid GUID format\n", *argv);
+				return -1;
+			}
+			addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_NODE_GUID,
+				  &ivg, sizeof(ivg));
+		} else if (matches(*argv, "port_guid") == 0) {
+			struct ifla_vf_guid ivg;
+
+			NEXT_ARG();
+			ivg.vf = vf;
+			if (get_guid(&ivg.guid, *argv)) {
+				invarg("Invalid GUID format\n", *argv);
+				return -1;
+			}
+			addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_PORT_GUID,
+				  &ivg, sizeof(ivg));
 		} else {
 			/* rewind arg */
 			PREV_ARG();
@@ -523,9 +551,11 @@
 				duparg("netns", *argv);
 			netns = netns_get_fd(*argv);
 			if (netns >= 0)
-				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
+				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD,
+					  &netns, 4);
 			else if (get_integer(&netns, *argv, 0) == 0)
-				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
+				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID,
+					  &netns, 4);
 			else
 				invarg("Invalid \"netns\" value\n", *argv);
 		} else if (strcmp(*argv, "multicast") == 0) {
@@ -689,7 +719,8 @@
 				invarg("Invalid address generation mode\n", *argv);
 			afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
 			afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
-			addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode);
+			addattr8(&req->n, sizeof(*req),
+				 IFLA_INET6_ADDR_GEN_MODE, mode);
 			addattr_nest_end(&req->n, afs6);
 			addattr_nest_end(&req->n, afs);
 		} else if (matches(*argv, "link-netnsid") == 0) {
@@ -728,10 +759,11 @@
 
 	if (dev_index && addr_len) {
 		int halen = nl_get_ll_addr_len(dev_index);
+
 		if (halen >= 0 && halen != addr_len) {
 			fprintf(stderr,
-			        "Invalid address length %d - must be %d bytes\n",
-			        addr_len, halen);
+				"Invalid address length %d - must be %d bytes\n",
+				addr_len, halen);
 			return -1;
 		}
 	}
@@ -759,7 +791,8 @@
 	req.n.nlmsg_type = cmd;
 	req.i.ifi_family = preferred_family;
 
-	ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group, &index);
+	ret = iplink_parse(argc, argv,
+			   &req, &name, &type, &link, &dev, &group, &index);
 	if (ret < 0)
 		return ret;
 
@@ -772,8 +805,8 @@
 					&group, sizeof(group));
 		else {
 			if (argc) {
-				fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link "
-						"help\".\n", *argv);
+				fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
+						*argv);
 				return -1;
 			}
 			if (flags & NLM_F_CREATE) {
@@ -830,7 +863,8 @@
 	if (name) {
 		len = strlen(name) + 1;
 		if (len == 1)
-			invarg("\"\" is not a valid device identifier\n", "name");
+			invarg("\"\" is not a valid device identifier\n",
+			       "name");
 		if (len > IFNAMSIZ)
 			invarg("\"name\" too long\n", name);
 		addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
@@ -859,7 +893,8 @@
 			iflatype = IFLA_INFO_DATA;
 		}
 		if (lu && argc) {
-			struct rtattr *data = addattr_nest(&req.n, sizeof(req), iflatype);
+			struct rtattr *data = addattr_nest(&req.n,
+							   sizeof(req), iflatype);
 
 			if (lu->parse_opt &&
 			    lu->parse_opt(lu, argc, argv, &req.n))
@@ -1090,7 +1125,8 @@
 	if (alen < 0)
 		return -1;
 	if (alen != halen) {
-		fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
+		fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n",
+			lla, halen);
 		return -1;
 	}
 	return 0;
@@ -1230,7 +1266,8 @@
 	}
 
 	if (!dev) {
-		fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
+		fprintf(stderr,
+			"Not enough of information: \"dev\" argument is required.\n");
 		exit(-1);
 	}
 
diff --git a/ip/iproute.c b/ip/iproute.c
index 24f6b01..c564fa6 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -1810,12 +1810,42 @@
 	return 0;
 }
 
+static int rtattr_cmp(const struct rtattr *rta1, const struct rtattr *rta2)
+{
+	if (!rta1 || !rta2 || rta1->rta_len != rta2->rta_len)
+		return 1;
+
+	return memcmp(RTA_DATA(rta1), RTA_DATA(rta2), RTA_PAYLOAD(rta1));
+}
+
 static int restore_handler(const struct sockaddr_nl *nl,
 			   struct rtnl_ctrl_data *ctrl,
 			   struct nlmsghdr *n, void *arg)
 {
-	int ret;
+	struct rtmsg *r = NLMSG_DATA(n);
+	struct rtattr *tb[RTA_MAX+1];
+	int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
+	int ret, prio = *(int *)arg;
 
+	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+
+	/* Restore routes in correct order:
+	 * 0. ones for local addresses,
+	 * 1. ones for local networks,
+	 * 2. others (remote networks/hosts).
+	 */
+	if (!prio && !tb[RTA_GATEWAY] && (!tb[RTA_PREFSRC] ||
+	    !rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST])))
+		goto restore;
+	else if (prio == 1 && !tb[RTA_GATEWAY] &&
+		 rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST]))
+		goto restore;
+	else if (prio == 2 && tb[RTA_GATEWAY])
+		goto restore;
+
+	return 0;
+
+restore:
 	n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
 
 	ll_init_map(&rth);
@@ -1848,10 +1878,23 @@
 
 static int iproute_restore(void)
 {
+	int pos, prio;
+
 	if (route_dump_check_magic())
 		exit(-1);
 
-	exit(rtnl_from_file(stdin, &restore_handler, NULL));
+	pos = ftell(stdin);
+	for (prio = 0; prio < 3; prio++) {
+		int err;
+
+		err = rtnl_from_file(stdin, &restore_handler, &prio);
+		if (err)
+			exit(err);
+
+		fseek(stdin, pos, SEEK_SET);
+	}
+
+	exit(0);
 }
 
 static int show_handler(const struct sockaddr_nl *nl,
diff --git a/lib/utils.c b/lib/utils.c
index 7dceeb5..9660474 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -1121,3 +1121,38 @@
 	sprintf(buf, "%d", val);
 	return buf;
 }
+
+int get_guid(__u64 *guid, const char *arg)
+{
+	unsigned long int tmp;
+	char *endptr;
+	int i;
+
+#define GUID_STR_LEN 23
+	/* Verify strict format: format string must be
+	 * xx:xx:xx:xx:xx:xx:xx:xx where xx can be an arbitrary
+	 * hex digit
+	 */
+
+	if (strlen(arg) != GUID_STR_LEN)
+		return -1;
+
+	/* make sure columns are in place */
+	for (i = 0; i < 7; i++)
+		if (arg[2 + i * 3] != ':')
+			return -1;
+
+	*guid = 0;
+	for (i = 0; i < 8; i++) {
+		tmp = strtoul(arg + i * 3, &endptr, 16);
+		if (endptr != arg + i * 3 + 2)
+			return -1;
+
+		if (tmp > 255)
+			return -1;
+
+		 *guid |= tmp << (56 - 8 * i);
+	}
+
+	return 0;
+}
diff --git a/man/man8/Makefile b/man/man8/Makefile
index 929826e..9badbed 100644
--- a/man/man8/Makefile
+++ b/man/man8/Makefile
@@ -16,7 +16,8 @@
 	tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \
 	tc-tcindex.8 tc-u32.8 \
 	tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \
-	tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8
+	tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \
+	devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8
 
 all: $(TARGETS)
 
diff --git a/man/man8/devlink.8 b/man/man8/devlink.8
index df00f4f..cf0563b 100644
--- a/man/man8/devlink.8
+++ b/man/man8/devlink.8
@@ -76,6 +76,7 @@
 .BR devlink-dev (8),
 .BR devlink-port (8),
 .BR devlink-monitor (8),
+.BR devlink-sb (8),
 .br
 
 .SH REPORTING BUGS
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index ad18f75..95fef02 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -146,7 +146,11 @@
 .br
 .RB "[ " state " { " auto " | " enable " | " disable " } ]"
 .br
-.RB "[ " trust " { " on " | " off " } ] ]"
+.RB "[ " trust " { " on " | " off " } ]"
+.br
+.RB "[ " node_guid " eui64 ]"
+.br
+.RB "[ " port_guid " eui64 ] ]"
 .br
 .in -9
 .RB "[ " master
@@ -1196,6 +1200,12 @@
 .BI trust " on|off"
 - trust the specified VF user. This enables that VF user can set a specific feature
 which may impact security and/or performance. (e.g. VF multicast promiscuous mode)
+.sp
+.BI node_guid " eui64"
+- configure node GUID for the VF.
+.sp
+.BI port_guid " eui64"
+- configure port GUID for the VF.
 .in -8
 
 .TP