optionally set socket priority on DHCPv4 raw socket

This commit is contained in:
chris 2023-01-01 14:59:20 +01:00 committed by Yu Watanabe
parent c24b0bd1df
commit ea57796854
12 changed files with 111 additions and 9 deletions

7
NEWS
View file

@ -48,6 +48,13 @@ CHANGES WITH 253 in spe:
* systemd-fstab-generator now supports x-systemd.makefs option for
/sysroot (in the initrd).
* The [DHCPv4] section in .network file gained new SocketPriority=
setting that assigns the Linux socket priority used by the DHCPv4
raw socket. Can be used in conjuntion with the EgressQOSMaps=setting in
[VLAN] section of .netdev file to send the desired ethernet 802.1Q frame
priority for DHCPv4 initial packets. This cannot be achieved with
netfilter mangle tables because of the raw socket bypass.
Changes in udev:
* The new net naming scheme "v253" has been introduced. In the new

View file

@ -1890,6 +1890,20 @@ allow my_server_t localnet_peer_t:peer recv;</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>SocketPriority=</varname></term>
<listitem>
<para>The Linux socket option <constant>SO_PRIORITY</constant> applied to the raw IP socket used for
initial DHCPv4 messages. Unset by default. Usual values range from 0 to 6.
More details about <constant>SO_PRIORITY</constant> socket option in
<citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
Can be used in conjunction with [VLAN] section <varname>EgressQOSMaps=</varname> setting of .netdev
file to set the 802.1Q VLAN ethernet tagged header priority, see
<citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
</listitem>
</varlistentry>
<!-- How to use the DHCP lease -->
<varlistentry>

View file

@ -40,7 +40,9 @@ int dhcp_network_bind_raw_socket(
const struct hw_addr_data *hw_addr,
const struct hw_addr_data *bcast_addr,
uint16_t arp_type,
uint16_t port);
uint16_t port,
bool so_priority_set,
int so_priority);
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);

View file

@ -25,7 +25,9 @@ static int _bind_raw_socket(
const struct hw_addr_data *hw_addr,
const struct hw_addr_data *bcast_addr,
uint16_t arp_type,
uint16_t port) {
uint16_t port,
bool so_priority_set,
int so_priority) {
assert(ifindex > 0);
assert(link);
@ -113,6 +115,12 @@ static int _bind_raw_socket(
if (r < 0)
return -errno;
if (so_priority_set) {
r = setsockopt_int(s, SOL_SOCKET, SO_PRIORITY, so_priority);
if (r < 0)
return r;
}
link->ll = (struct sockaddr_ll) {
.sll_family = AF_PACKET,
.sll_protocol = htobe16(ETH_P_IP),
@ -137,7 +145,9 @@ int dhcp_network_bind_raw_socket(
const struct hw_addr_data *hw_addr,
const struct hw_addr_data *bcast_addr,
uint16_t arp_type,
uint16_t port) {
uint16_t port,
bool so_priority_set,
int so_priority) {
static struct hw_addr_data default_eth_bcast = {
.length = ETH_ALEN,
@ -160,13 +170,13 @@ int dhcp_network_bind_raw_socket(
return _bind_raw_socket(ifindex, link, xid,
hw_addr,
(bcast_addr && !hw_addr_is_null(bcast_addr)) ? bcast_addr : &default_eth_bcast,
arp_type, port);
arp_type, port, so_priority_set, so_priority);
case ARPHRD_INFINIBAND:
return _bind_raw_socket(ifindex, link, xid,
&HW_ADDR_NULL,
(bcast_addr && !hw_addr_is_null(bcast_addr)) ? bcast_addr : &default_ib_bcast,
arp_type, port);
arp_type, port, so_priority_set, so_priority);
default:
return -EINVAL;
}

View file

@ -16,7 +16,10 @@ int dhcp_network_bind_raw_socket(
uint32_t id,
const struct hw_addr_data *hw_addr,
const struct hw_addr_data *bcast_addr,
uint16_t arp_type, uint16_t port) {
uint16_t arp_type,
uint16_t port,
bool so_priority_set,
int so_priority) {
int fd;
fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);

View file

@ -121,6 +121,8 @@ struct sd_dhcp_client {
sd_dhcp_lease *lease;
usec_t start_delay;
int ip_service_type;
int socket_priority;
bool socket_priority_set;
/* Ignore machine-ID when generating DUID. See dhcp_identifier_set_duid_en(). */
bool test_mode;
@ -647,6 +649,16 @@ int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
return 0;
}
int sd_dhcp_client_set_socket_priority(sd_dhcp_client *client, int socket_priority) {
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
client->socket_priority_set = true;
client->socket_priority = socket_priority;
return 0;
}
int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) {
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
@ -1381,7 +1393,8 @@ static int client_start_delayed(sd_dhcp_client *client) {
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
&client->hw_addr, &client->bcast_addr,
client->arp_type, client->port);
client->arp_type, client->port,
client->socket_priority_set, client->socket_priority);
if (r < 0) {
client_stop(client, r);
return r;
@ -1429,7 +1442,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
&client->hw_addr, &client->bcast_addr,
client->arp_type, client->port);
client->arp_type, client->port,
client->socket_priority_set, client->socket_priority);
if (r < 0) {
client_stop(client, r);
return 0;

View file

@ -235,7 +235,10 @@ int dhcp_network_bind_raw_socket(
uint32_t id,
const struct hw_addr_data *_hw_addr,
const struct hw_addr_data *_bcast_addr,
uint16_t arp_type, uint16_t port) {
uint16_t arp_type,
uint16_t port,
bool so_priority_set,
int so_priority) {
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
return -errno;

View file

@ -1499,6 +1499,12 @@ static int dhcp4_configure(Link *link) {
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IP service type: %m");
}
if (link->network->dhcp_socket_priority_set) {
r = sd_dhcp_client_set_socket_priority(link->dhcp_client, link->network->dhcp_socket_priority);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set socket priority: %m");
}
if (link->network->dhcp_fallback_lease_lifetime > 0) {
r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
if (r < 0)
@ -1701,6 +1707,42 @@ int config_parse_dhcp_ip_service_type(
return 0;
}
int config_parse_dhcp_socket_priority(
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) {
Network *network = ASSERT_PTR(data);
int a, r;
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
network->dhcp_socket_priority_set = false;
return 0;
}
r = safe_atoi(rvalue, &a);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse socket priority, ignoring: %s", rvalue);
return 0;
}
network->dhcp_socket_priority_set = true;
network->dhcp_socket_priority = a;
return 0;
}
int config_parse_dhcp_fallback_lease_lifetime(
const char *unit,
const char *filename,

View file

@ -29,6 +29,7 @@ int link_request_dhcp4_client(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_socket_priority);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_fallback_lease_lifetime);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_label);

View file

@ -243,6 +243,7 @@ DHCPv4.SendDecline, config_parse_bool,
DHCPv4.DenyList, config_parse_in_addr_prefixes, AF_INET, offsetof(Network, dhcp_deny_listed_ip)
DHCPv4.AllowList, config_parse_in_addr_prefixes, AF_INET, offsetof(Network, dhcp_allow_listed_ip)
DHCPv4.IPServiceType, config_parse_dhcp_ip_service_type, 0, offsetof(Network, dhcp_ip_service_type)
DHCPv4.SocketPriority, config_parse_dhcp_socket_priority, 0, 0
DHCPv4.SendOption, config_parse_dhcp_send_option, AF_INET, offsetof(Network, dhcp_client_send_options)
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
DHCPv4.RouteMTUBytes, config_parse_mtu, AF_INET, offsetof(Network, dhcp_route_mtu)

View file

@ -130,6 +130,8 @@ struct Network {
uint16_t dhcp_client_port;
int dhcp_critical;
int dhcp_ip_service_type;
int dhcp_socket_priority;
bool dhcp_socket_priority_set;
bool dhcp_anonymize;
bool dhcp_send_hostname;
int dhcp_broadcast;

View file

@ -309,6 +309,9 @@ int sd_dhcp_client_get_lease(
int sd_dhcp_client_set_service_type(
sd_dhcp_client *client,
int type);
int sd_dhcp_client_set_socket_priority(
sd_dhcp_client *client,
int so_priority);
int sd_dhcp_client_set_fallback_lease_lifetime(
sd_dhcp_client *client,
uint32_t fallback_lease_lifetime);