]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
optionally set socket priority on DHCPv4 raw socket
authorchris <chris@debian11>
Sun, 1 Jan 2023 13:59:20 +0000 (14:59 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 12 Jan 2023 04:26:47 +0000 (13:26 +0900)
12 files changed:
NEWS
man/systemd.network.xml
src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-network.c
src/libsystemd-network/fuzz-dhcp-client.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/test-dhcp-client.c
src/network/networkd-dhcp4.c
src/network/networkd-dhcp4.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.h
src/systemd/sd-dhcp-client.h

diff --git a/NEWS b/NEWS
index 7e1e53606050dcc76d816f5ca643f760b81ee943..4358d0c48efe3e4307cc130b7d9cc8cb2b7e44af 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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
index ccdbc49b1d87aec3bc4d6d5e047669fcba717ff6..daa2c2e167457cba6f6f16aecb901a270379bdc8 100644 (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>
index a311d1d5b9129d3d150ee4338e7b66292d33d26f..5a7308c5ac3968ccbd4ae955fe4dcdf26951fce2 100644 (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);
index 4e4b1ccb751b097c5a89ce56a3f36962c058807a..9137efa3ee1f36ddb3e0e883da3f30f2fc1084d3 100644 (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;
         }
index a9cfba90e3d769f9242b44c6523ab96769dab192..d2bbf660b0d1af7fac4950f02629be96d661f5f8 100644 (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);
index 48174e7c4b0f9848c300192d2faa5444a8b14944..f5abb1bf861f2a8c6041c227018604f1f32aec2c 100644 (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;
index 92b9b5b9bc558dbd0370294d13b66fea534cac0c..863649f6df5e77e7c0cb88ac1e4ec3cc9227fc71 100644 (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;
index e4005719d05065068e7c435f0a1a231e09494801..43850e1e954b6925658c9d6b0bffc2620d30461c 100644 (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,
index 1d30cd15dfba04ba9c65eb6f9c4d494c6eae55fe..0f14e0794333c28bd69225d5278312512b071010 100644 (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);
index 762eef5b915332b2ad5be386a44a348a66caddcc..c205e56c629529b966d1c317c481e6558e4c4c31 100644 (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)
index 79e8ceb06b41d038155434152c1a2d0244f586f7..09f0e9beea007341766751cfcfc413018de03964 100644 (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;
index b200f17cbdd5dde0744216dd9e13cc60723c2826..2b3f995769837e23bfaea63b3e5d2d50180b84e8 100644 (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);