diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 585041095d..e5f9d6f470 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1309,7 +1309,14 @@
Note that if IPv6 is enabled on the interface, and the MTU is chosen
below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value.
-
+
+
+ IPServiceType=
+
+ Takes string; "CS6" or "CS4". Used to set IP service type to CS6 (network control)
+ or CS4 (Realtime). IPServiceType defaults to CS6 if nothing is specified.
+
+
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index e0269b5456..c231773bdd 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -19,7 +19,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
uint32_t xid, const uint8_t *mac_addr,
size_t mac_addr_len, uint16_t arp_type,
uint16_t port);
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port);
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
const void *packet, size_t len);
int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
@@ -41,7 +41,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
uint16_t source, be32_t destination_addr,
- uint16_t destination, uint16_t len);
+ uint16_t destination, uint16_t len, int ip_service_type);
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c
index 94c10ed14c..8e7f8a65ab 100644
--- a/src/libsystemd-network/dhcp-network.c
+++ b/src/libsystemd-network/dhcp-network.c
@@ -146,7 +146,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
bcast_addr, ð_mac, arp_type, dhcp_hlen, port);
}
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
union sockaddr_union src = {
.in.sin_family = AF_INET,
.in.sin_port = htobe16(port),
@@ -159,7 +159,11 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
if (s < 0)
return -errno;
- r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
+ if (ip_service_type >= 0)
+ r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type);
+ else
+ r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
+
if (r < 0)
return r;
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index ad5f8e267a..fe7d51703b 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -75,12 +75,15 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
uint16_t source_port, be32_t destination_addr,
- uint16_t destination_port, uint16_t len) {
+ uint16_t destination_port, uint16_t len, int ip_service_type) {
packet->ip.version = IPVERSION;
packet->ip.ihl = DHCP_IP_SIZE / 4;
packet->ip.tot_len = htobe16(len);
- packet->ip.tos = IPTOS_CLASS_CS6;
+ if (ip_service_type >= 0)
+ packet->ip.tos = ip_service_type;
+ else
+ packet->ip.tos = IPTOS_CLASS_CS6;
packet->ip.protocol = IPPROTO_UDP;
packet->ip.saddr = source_addr;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index cadacc24d4..2d511f7feb 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -98,6 +98,7 @@ struct sd_dhcp_client {
void *userdata;
sd_dhcp_lease *lease;
usec_t start_delay;
+ int ip_service_type;
};
static const uint8_t default_req_opts[] = {
@@ -541,6 +542,14 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
return 0;
}
+int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
+ assert_return(client, -EINVAL);
+
+ client->ip_service_type = type;
+
+ return 0;
+}
+
static int client_notify(sd_dhcp_client *client, int event) {
assert(client);
@@ -773,7 +782,7 @@ static int dhcp_client_send_raw(
size_t len) {
dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
- INADDR_BROADCAST, DHCP_PORT_SERVER, len);
+ INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type);
return dhcp_network_send_raw_socket(client->fd, &client->link,
packet, len);
@@ -1661,7 +1670,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
goto error;
}
- r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
+ r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type);
if (r < 0) {
log_dhcp_client(client, "could not bind UDP socket");
goto error;
@@ -2013,6 +2022,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
.port = DHCP_PORT_CLIENT,
.anonymize = !!anonymize,
.max_attempts = (uint64_t) -1,
+ .ip_service_type = -1,
};
/* NOTE: this could be moved to a function. */
if (anonymize) {
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 13f104f9ef..bba82c21dd 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -244,7 +244,7 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
packet->dhcp.yiaddr,
- DHCP_PORT_CLIENT, len);
+ DHCP_PORT_CLIENT, len, -1);
return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
}
@@ -994,7 +994,7 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
}
server->fd_raw = r;
- r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER);
+ r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
if (r < 0) {
sd_dhcp_server_stop(server);
return r;
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index 5f31d24d20..4e9b388a45 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -269,7 +269,7 @@ int dhcp_network_bind_raw_socket(
return test_fd[0];
}
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
int fd;
fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c
index 1ef5beb203..eef7788c49 100644
--- a/src/network/networkd-conf.c
+++ b/src/network/networkd-conf.c
@@ -4,6 +4,7 @@
***/
#include
+#include
#include "conf-parser.h"
#include "def.h"
@@ -14,6 +15,7 @@
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-speed-meter.h"
+#include "networkd-dhcp4.h"
#include "string-table.h"
int manager_parse_config_file(Manager *m) {
@@ -180,3 +182,30 @@ int config_parse_duid_rawdata(
ret->raw_data_len = count;
return 0;
}
+
+int config_parse_ip_service_type(
+ 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) {
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (streq(rvalue, "CS4"))
+ *((int *)data) = IPTOS_CLASS_CS4;
+ else if (streq(rvalue, "CS6"))
+ *((int *)data) = IPTOS_CLASS_CS6;
+ else
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Failed to parse IPServiceType type '%s', ignoring.", rvalue);
+
+ return 0;
+}
diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h
index 88a2c64031..a615998f92 100644
--- a/src/network/networkd-conf.h
+++ b/src/network/networkd-conf.h
@@ -15,3 +15,4 @@ const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, GPERF_LEN_TY
CONFIG_PARSER_PROTOTYPE(config_parse_duid_type);
CONFIG_PARSER_PROTOTYPE(config_parse_duid_rawdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip_service_type);
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 06e87199c6..78cd241140 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -1213,7 +1213,12 @@ int dhcp4_configure(Link *link) {
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
}
- return dhcp4_set_client_identifier(link);
+ if (link->network->ip_service_type > 0) {
+ r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->ip_service_type);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m");
+ }
+ return dhcp4_set_client_identifier(link);
}
int config_parse_dhcp_max_attempts(
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 11e541e093..ce9fc30162 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -167,6 +167,7 @@ DHCPv4.IAID, config_parse_iaid,
DHCPv4.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
DHCPv4.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp_send_release)
DHCPv4.BlackList, config_parse_dhcp_black_listed_ip_address, 0, 0
+DHCPv4.IPServiceType, config_parse_ip_service_type, 0, offsetof(Network, ip_service_type)
DHCPv6.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp6_use_dns)
DHCPv6.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp6_use_ntp)
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index a2cd7f4c60..23a21d8c9e 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -442,6 +442,7 @@ int network_load_one(Manager *manager, const char *filename) {
.keep_configuration = _KEEP_CONFIGURATION_INVALID,
.can_triple_sampling = -1,
+ .ip_service_type = -1,
};
r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 837206a29c..ff97845dd1 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -104,6 +104,7 @@ struct Network {
DHCPUseDomains dhcp_use_domains;
Set *dhcp_black_listed_ip;
Set *dhcp_request_options;
+ int ip_service_type;
/* DHCPv6 Client support*/
bool dhcp6_use_dns;
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index d2d74b2b4c..98e3281397 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -174,6 +174,9 @@ int sd_dhcp_client_set_user_class(
int sd_dhcp_client_get_lease(
sd_dhcp_client *client,
sd_dhcp_lease **ret);
+int sd_dhcp_client_set_service_type(
+ sd_dhcp_client *client,
+ int type);
int sd_dhcp_client_stop(sd_dhcp_client *client);
int sd_dhcp_client_start(sd_dhcp_client *client);
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 3be643075a..78cddcab77 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -93,6 +93,7 @@ BlackList=
RequestOptions=
SendRelease=
MaxAttempts=
+IPServiceType=
[DHCPv6]
UseNTP=
UseDNS=