diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 5968c16b21..7c31f345ab 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -269,6 +269,14 @@
+
+ VLANProtocol=
+
+ Specifies VLAN protocol of the virtual function. Takes 802.1Q or
+ 802.1ad.
+
+
+
MACSpoofCheck=
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index fe640bd2b0..f1937ac251 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -57,6 +57,7 @@ Link.RequiredForOnline, config_parse_required_for_online,
SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, 0
SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, 0
SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, 0
+SR-IOV.VLANProtocol, config_parse_sr_iov_vlan_proto, 0, 0
SR-IOV.MACSpoofCheck, config_parse_sr_iov_boolean, 0, 0
SR-IOV.QueryReceiveSideScaling, config_parse_sr_iov_boolean, 0, 0
SR-IOV.Trust, config_parse_sr_iov_boolean, 0, 0
diff --git a/src/network/networkd-sriov.c b/src/network/networkd-sriov.c
index 63d0d1443d..62a6fc9c22 100644
--- a/src/network/networkd-sriov.c
+++ b/src/network/networkd-sriov.c
@@ -18,6 +18,7 @@ static int sr_iov_new(SRIOV **ret) {
*sr_iov = (SRIOV) {
.vf = (uint32_t) -1,
+ .vlan_proto = ETH_P_8021Q,
.vf_spoof_check_setting = -1,
.trust = -1,
.query_rss = -1,
@@ -180,7 +181,7 @@ int sr_iov_configure(Link *link, SRIOV *sr_iov) {
ivvi.vf = sr_iov->vf;
ivvi.vlan = sr_iov->vlan;
ivvi.qos = sr_iov->qos;
- ivvi.vlan_proto = htobe16(ETH_P_8021Q);
+ ivvi.vlan_proto = htobe16(sr_iov->vlan_proto);
r = sd_netlink_message_open_container(req, IFLA_VF_VLAN_LIST);
if (r < 0)
@@ -297,6 +298,45 @@ int config_parse_sr_iov_uint32(
return 0;
}
+int config_parse_sr_iov_vlan_proto(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+ Network *network = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = sr_iov_new_static(network, filename, section_line, &sr_iov);
+ if (r < 0)
+ return r;
+
+ if (isempty(rvalue) || streq(rvalue, "802.1Q"))
+ sr_iov->vlan_proto = ETH_P_8021Q;
+ else if (streq(rvalue, "802.1ad"))
+ sr_iov->vlan_proto = ETH_P_8021AD;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Invalid SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ TAKE_PTR(sr_iov);
+ return 0;
+}
+
int config_parse_sr_iov_link_state(
const char *unit,
const char *filename,
diff --git a/src/network/networkd-sriov.h b/src/network/networkd-sriov.h
index d9668d7b65..65ad3266b3 100644
--- a/src/network/networkd-sriov.h
+++ b/src/network/networkd-sriov.h
@@ -24,6 +24,7 @@ typedef struct SRIOV {
uint32_t vf; /* 0 - 2147483646 */
uint32_t vlan; /* 0 - 4095, 0 disables VLAN filter */
uint32_t qos;
+ uint16_t vlan_proto; /* ETH_P_8021Q or ETH_P_8021AD */
int vf_spoof_check_setting;
int query_rss;
int trust;
@@ -40,3 +41,4 @@ DEFINE_NETWORK_SECTION_FUNCTIONS(SRIOV, sr_iov_free);
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_uint32);
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_boolean);
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_vlan_proto);
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 0066cbda18..c5bab2abf8 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -42,6 +42,7 @@ Group=
VirtualFunction=
MACSpoofCheck=
VLANId=
+VLANProtocol=
QualityOfService=
QueryReceiveSideScaling=
Trust=