diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6304add..ff29803 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -698,6 +698,8 @@ enum {
 	IFLA_VF_VLAN_LIST,	/* nested list of vlans, option for QinQ */
 	IFLA_VF_BROADCAST,	/* VF broadcast */
 	IFLA_VF_VLAN_MODE,	/* vlan tagging mode */
+	IFLA_VF_VLAN_RANGE,	/* VF add/remove vlan-ids range */
+	IFLA_VF_VLAN_TRUNK,	/* VF allowed vlan-ids trunk */
 	__IFLA_VF_MAX,
 };
 
@@ -747,6 +749,23 @@ struct ifla_vf_vlan_info {
 	__be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */
 };
 
+struct ifla_vf_vlan_range {
+	__u32 vf;
+	__u32 start_vid;   /* 0 - 4095, 0 - for untagged and priority tagged */
+	__u32 end_vid;     /* 0 - 4095, 0 - for untagged and priority tagged */
+	__u32 setting;     /* 0 : Add range , 1 : Remove range */
+	__be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */
+};
+
+#define BITS_PER_BYTE		8
+#define VLAN_N_VID		4096
+#define VF_VLAN_BITMAP		__KERNEL_DIV_ROUND_UP(VLAN_N_VID, sizeof(__u64) * BITS_PER_BYTE)
+struct ifla_vf_vlan_trunk {
+	__u32 vf;
+	__u64 trunk_vid_8021q_bitmap[VF_VLAN_BITMAP];
+	__u64 trunk_vid_8021ad_bitmap[VF_VLAN_BITMAP];
+};
+
 struct ifla_vf_tx_rate {
 	__u32 vf;
 	__u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index a66ca02..90efbff 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -350,6 +350,7 @@ static void print_af_spec(FILE *fp, struct rtattr *af_spec_attr)
 }
 
 static void print_vf_stats64(FILE *fp, struct rtattr *vfstats);
+static void print_vf_vlan_trunk(FILE *fp, __u64 *bitmap, const char *proto);
 
 static void print_vfinfo(FILE *fp, struct ifinfomsg *ifi, struct rtattr *vfinfo)
 {
@@ -548,6 +549,18 @@ static void print_vfinfo(FILE *fp, struct ifinfomsg *ifi, struct rtattr *vfinfo)
 
 	if (vf[IFLA_VF_STATS] && show_stats)
 		print_vf_stats64(fp, vf[IFLA_VF_STATS]);
+
+	/*
+	 * VF trunk query should always be the last if-condition because it adds
+	 * new lines to the end of the vf info output.
+	 */
+	if (vf[IFLA_VF_VLAN_TRUNK]) {
+		struct ifla_vf_vlan_trunk *vf_trunk =
+				RTA_DATA(vf[IFLA_VF_VLAN_TRUNK]);
+
+		print_vf_vlan_trunk(fp, vf_trunk->trunk_vid_8021q_bitmap, "802.1Q");
+		print_vf_vlan_trunk(fp, vf_trunk->trunk_vid_8021ad_bitmap, "802.1ad");
+	}
 }
 
 void print_num(FILE *fp, unsigned int width, uint64_t count)
@@ -590,6 +603,45 @@ void print_num(FILE *fp, unsigned int width, uint64_t count)
 	fprintf(fp, "%-*s ", width, buf);
 }
 
+static void print_vf_vlan_trunk(FILE *fp, __u64 *bitmap, const char *proto)
+{
+#define VF_VLAN_TRUNK_LINE_SZ	100
+	int vids_per_dword = sizeof(bitmap[0]) * 8;
+	char trunk_line[2 * VF_VLAN_TRUNK_LINE_SZ] = {0};
+	bool printed_title = false;
+	bool need_newline = false;
+	int vid;
+
+	for (vid = 0; vid < VLAN_N_VID ; vid++) {
+		if ((bitmap[vid / vids_per_dword] >> (vid % vids_per_dword)) & 0x1) {
+			if (strlen(trunk_line) >= VF_VLAN_TRUNK_LINE_SZ)
+				need_newline = true;
+
+			if (!printed_title) {
+				sprintf(trunk_line,
+					"\n    Allowed %s VLANs: ", proto);
+				printed_title = true;
+			}
+
+			if (need_newline) {
+				fprintf(fp, "%s", trunk_line);
+				trunk_line[0] = '\0';
+			}
+
+			sprintf(trunk_line, "%s%s%d, ", trunk_line,
+				(need_newline ? "\n    " : ""), vid);
+
+			need_newline = false;
+		}
+	}
+
+	if (strlen(trunk_line)) {
+		trunk_line[strlen(trunk_line) - 2] = '.';
+		trunk_line[strlen(trunk_line) - 1] = '\0';
+		fprintf(fp, "%s", trunk_line);
+	}
+}
+
 static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
 {
 	struct rtattr *vf[IFLA_VF_STATS_MAX + 1];
diff --git a/ip/iplink.c b/ip/iplink.c
index ef33232..31076fc 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -89,6 +89,7 @@ void iplink_usage(void)
 		"			[ alias NAME ]\n"
 		"			[ vf NUM [ mac LLADDR ]\n"
 		"				 [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"
+		"				 [ trunk { add | rem } START-VLANID [ END-VLANID ] [ proto VLAN-PROTO ] ]\n"
 		"				 [ rate TXRATE ]\n"
 		"				 [ max_tx_rate TXRATE ]\n"
 		"				 [ min_tx_rate TXRATE ]\n"
@@ -429,6 +430,51 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
 				}
 				addattr_nest_end(&req->n, vfvlanlist);
 			}
+		} else if (matches(*argv, "trunk") == 0) {
+			struct ifla_vf_vlan_range ivvr;
+
+			ivvr.vf = vf;
+			ivvr.vlan_proto = htons(ETH_P_8021Q);
+			NEXT_ARG();
+			if (matches(*argv, "add") && matches(*argv, "rem"))
+				invarg("Invalid \"trunk\" operation\n", *argv);
+			ivvr.setting = !matches(*argv, "add");
+			NEXT_ARG();
+			if (get_unsigned(&ivvr.start_vid, *argv, 0))
+				invarg("Invalid \"trunk\" start value\n", *argv);
+			ivvr.end_vid = ivvr.start_vid;
+			if (NEXT_ARG_OK()) {
+				NEXT_ARG();
+				if (get_unsigned(&ivvr.end_vid, *argv, 0))
+					PREV_ARG();
+			}
+			if (NEXT_ARG_OK()) {
+				NEXT_ARG();
+				if (matches(*argv, "proto") == 0) {
+					NEXT_ARG();
+					if (ll_proto_a2n(&ivvr.vlan_proto, *argv))
+						invarg("protocol is invalid\n", *argv);
+					if (ivvr.vlan_proto != htons(ETH_P_8021AD) &&
+					    ivvr.vlan_proto != htons(ETH_P_8021Q)) {
+						SPRINT_BUF(b1);
+						SPRINT_BUF(b2);
+						char msg[64 + sizeof(b1) + sizeof(b2)];
+
+						sprintf(msg,
+							"Invalid \"vlan protocol\" value - supported %s, %s\n",
+							ll_proto_n2a(htons(ETH_P_8021Q),
+								     b1, sizeof(b1)),
+							ll_proto_n2a(htons(ETH_P_8021AD),
+								     b2, sizeof(b2)));
+						invarg(msg, *argv);
+					}
+				} else {
+					/* rewind arg */
+					PREV_ARG();
+				}
+			}
+			addattr_l(&req->n, sizeof(*req),
+				  IFLA_VF_VLAN_RANGE, &ivvr, sizeof(ivvr));
 		} else if (matches(*argv, "rate") == 0) {
 			struct ifla_vf_tx_rate ivt;
 
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index 29744d4..23f6235 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -128,7 +128,12 @@ ip-link \- network device configuration
 .br
 .RB "[ " node_guid " eui64 ]"
 .br
-.RB "[ " port_guid " eui64 ] ]"
+.RB "[ " port_guid " eui64 ]"
+.br
+.RB "[ " trunk " { " add " | " rem " } "
+.IR START-VLAN-ID " [ " END-VLAN-ID " ] "
+.RB "[ " proto
+.IR VLAN-PROTO " ] ] ] "
 .br
 .in -9
 .RB "[ { " xdp " | " xdpgeneric  " | " xdpdrv " | " xdpoffload " } { " off " | "
@@ -2043,6 +2048,16 @@ performance. (e.g. VF multicast promiscuous mode)
 .sp
 .BI port_guid " eui64"
 - configure port GUID for Infiniband VFs.
+.sp
+.BI trunk " add|rem START-VLANID [END-VLANID] [proto VLAN-PROTO] "
+- add or remove allowed vlan-ids range that can be used by the VF. Range 0-4095
+while 0 is used for untagged and priority tagged traffic.
+.B vf
+parameter must be specified.
+.B END-VLANID
+parameter is optional. If omitted, assumes range of one vlan-id.
+.B proto
+parameter is optional, either 802.1Q or 802.1ad. If omitted, assumes 802.1Q.
 .in -8
 
 .TP
