dhcp4: make IPServiceType configurable

IPServiceType set to CS6 (network control) causes problems on some old
network setups that continue to interpret the field as IP TOS.

Make DHCP work on such networks by allowing this field to be set to
CS4 (Realtime) instead, as this maps to IPTOS_LOWDELAY.

Signed-off-by: Siddharth Chandrasekaran <csiddharth@vmware.com>
This commit is contained in:
Siddharth Chandrasekara 2019-09-23 04:25:21 -07:00 committed by Yu Watanabe
parent 55a1729fd0
commit afe42aef39
15 changed files with 79 additions and 13 deletions

View file

@ -1309,7 +1309,14 @@
<para>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.</para>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<term><varname>IPServiceType=</varname></term>
<listitem>
<para>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.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View file

@ -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);

View file

@ -146,7 +146,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
bcast_addr, &eth_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;

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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);

View file

@ -4,6 +4,7 @@
***/
#include <ctype.h>
#include <netinet/ip.h>
#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;
}

View file

@ -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);

View file

@ -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(

View file

@ -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)

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -93,6 +93,7 @@ BlackList=
RequestOptions=
SendRelease=
MaxAttempts=
IPServiceType=
[DHCPv6]
UseNTP=
UseDNS=