diff --git a/.systemd.metadata b/.systemd.metadata
index f971042..052ad4c 100644
--- a/.systemd.metadata
+++ b/.systemd.metadata
@@ -1 +1 @@
-9fdcf03e0c88b3aa98c95626a588311084ef9047 SOURCES/systemd-249.2.tar.gz
+5e3b9df64a15cb3b446c0e74556ea9020ce50b8b SOURCES/systemd-249.4.tar.gz
diff --git a/SOURCES/20458.patch b/SOURCES/20458.patch
new file mode 100644
index 0000000..ad916b4
--- /dev/null
+++ b/SOURCES/20458.patch
@@ -0,0 +1,143 @@
+From e9f92c88163841d3f1d29fa5b44ae4c6f71bb014 Mon Sep 17 00:00:00 2001
+From: Daan De Meyer <daan.j.demeyer@gmail.com>
+Date: Wed, 18 Aug 2021 07:59:13 +0100
+Subject: [PATCH] udev: Support "max" string for BufferSize options (#20458)
+
+"max" indicates the hardware advertised maximum queue buffer size
+should be used.
+
+The max sizes can be checked by running `ethtool -g <dev>` (Preset maximums).
+Since the buffer sizes can't be set to 0 by users, internally we use 0 to
+indicate that the hardware advertised maximum should be used.
+---
+ man/systemd.link.xml      | 20 ++++++++++++--------
+ src/shared/ethtool-util.c | 40 +++++++++++++++++++++++++--------------
+ src/shared/ethtool-util.h |  2 ++
+ 3 files changed, 40 insertions(+), 22 deletions(-)
+
+diff --git a/man/systemd.link.xml b/man/systemd.link.xml
+index 1c18f35fc8..fd744ebaed 100644
+--- a/man/systemd.link.xml
++++ b/man/systemd.link.xml
+@@ -735,29 +735,33 @@
+       <varlistentry>
+         <term><varname>RxBufferSize=</varname></term>
+         <listitem>
+-          <para>Takes an integer. Specifies the maximum number of pending packets in the NIC receive buffer.
+-          When unset, the kernel's default will be used.</para>
++          <para>Takes an integer or <literal>max</literal>. Specifies the maximum number of pending packets
++          in the NIC receive buffer. When unset, the kernel's default will be used. If set to
++          <literal>max</literal>, the hardware's advertised maximum size will be used.</para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term><varname>RxMiniBufferSize=</varname></term>
+         <listitem>
+-          <para>Takes an integer. Specifies the maximum number of pending packets in the NIC mini receive buffer.
+-          When unset, the kernel's default will be used.</para>
++          <para>Takes an integer or <literal>max</literal>. Specifies the maximum number of pending packets
++          in the NIC mini receive buffer. When unset, the kernel's default will be used. If set to
++          <literal>max</literal>, the hardware's advertised maximum size will be used.</para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term><varname>RxJumboBufferSize=</varname></term>
+         <listitem>
+-          <para>Takes an integer. Specifies the maximum number of pending packets in the NIC jumbo receive buffer.
+-          When unset, the kernel's default will be used.</para>
++          <para>Takes an integer or <literal>max</literal>. Specifies the maximum number of pending packets
++          in the NIC jumbo receive buffer. When unset, the kernel's default will be used. If set to
++          <literal>max</literal>, the hardware's advertised maximum size will be used.</para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term><varname>TxBufferSize=</varname></term>
+         <listitem>
+-          <para>Takes an integer. Specifies the maximum number of pending packets in the NIC transmit buffer.
+-          When unset, the kernel's default will be used.</para>
++          <para>Takes an integer or <literal>max</literal>. Specifies the maximum number of pending packets
++          in the NIC transmit buffer. When unset, the kernel's default will be used. If set to
++          <literal>max</literal>, the hardware's advertised maximum size will be used.</para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c
+index f77f6943ca..ed251ec8dd 100644
+--- a/src/shared/ethtool-util.c
++++ b/src/shared/ethtool-util.c
+@@ -399,16 +399,24 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde
+                 return -errno;
+ 
+         if (ring->rx_pending_set)
+-                UPDATE(ecmd.rx_pending, ring->rx_pending, need_update);
++                UPDATE(ecmd.rx_pending,
++                       ring->rx_pending == 0 ? ecmd.rx_max_pending : ring->rx_pending,
++                       need_update);
+ 
+         if (ring->rx_mini_pending_set)
+-                UPDATE(ecmd.rx_mini_pending, ring->rx_mini_pending, need_update);
++                UPDATE(ecmd.rx_mini_pending,
++                       ring->rx_mini_pending == 0 ? ecmd.rx_mini_max_pending : ring->rx_mini_pending,
++                       need_update);
+ 
+         if (ring->rx_jumbo_pending_set)
+-                UPDATE(ecmd.rx_jumbo_pending, ring->rx_jumbo_pending, need_update);
++                UPDATE(ecmd.rx_jumbo_pending,
++                       ring->rx_jumbo_pending == 0 ? ecmd.rx_jumbo_max_pending : ring->rx_jumbo_pending,
++                       need_update);
+ 
+         if (ring->tx_pending_set)
+-                UPDATE(ecmd.tx_pending, ring->tx_pending, need_update);
++                UPDATE(ecmd.tx_pending,
++                       ring->tx_pending == 0 ? ecmd.tx_max_pending : ring->tx_pending,
++                       need_update);
+ 
+         if (!need_update)
+                 return 0;
+@@ -1037,16 +1045,20 @@ int config_parse_nic_buffer_size(
+         assert(rvalue);
+         assert(data);
+ 
+-        r = safe_atou32(rvalue, &k);
+-        if (r < 0) {
+-                log_syntax(unit, LOG_WARNING, filename, line, r,
+-                           "Failed to parse interface buffer value, ignoring: %s", rvalue);
+-                return 0;
+-        }
+-        if (k < 1) {
+-                log_syntax(unit, LOG_WARNING, filename, line, 0,
+-                           "Invalid %s= value, ignoring: %s", lvalue, rvalue);
+-                return 0;
++        if (streq(rvalue, "max"))
++                k = 0;
++        else {
++                r = safe_atou32(rvalue, &k);
++                if (r < 0) {
++                        log_syntax(unit, LOG_WARNING, filename, line, r,
++                                "Failed to parse interface buffer value, ignoring: %s", rvalue);
++                        return 0;
++                }
++                if (k < 1) {
++                        log_syntax(unit, LOG_WARNING, filename, line, 0,
++                                "Invalid %s= value, ignoring: %s", lvalue, rvalue);
++                        return 0;
++                }
+         }
+ 
+         if (streq(lvalue, "RxBufferSize")) {
+diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h
+index 7d28766624..aea131914e 100644
+--- a/src/shared/ethtool-util.h
++++ b/src/shared/ethtool-util.h
+@@ -70,6 +70,8 @@ typedef struct netdev_channels {
+ } netdev_channels;
+ 
+ typedef struct netdev_ring_param {
++        /* For any of the 4 following settings, a value of 0 indicates the hardware advertised maximum should
++         * be used. */
+         uint32_t rx_pending;
+         uint32_t rx_mini_pending;
+         uint32_t rx_jumbo_pending;
+-- 
+2.31.1
+
diff --git a/SOURCES/20472.patch b/SOURCES/20472.patch
new file mode 100644
index 0000000..e5eb57b
--- /dev/null
+++ b/SOURCES/20472.patch
@@ -0,0 +1,425 @@
+From 78e57b79c8790448412acca41e5d4495366305a6 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 18 Aug 2021 16:41:11 +0900
+Subject: [PATCH] udev: make RxChannels= or friends also accept "max"
+
+Follow-up for 406041b7de767316674eb6a2f98ad466577ce8a4.
+
+Also, this makes
+- the settings accept an empty string,
+- if the specified value is too large, also use the advertised maximum
+  value.
+- mention the range of the value in the man page.
+---
+ man/systemd.link.xml                 |  49 ++------
+ src/shared/ethtool-util.c            | 170 ++++++++++-----------------
+ src/shared/ethtool-util.h            |  36 +++---
+ src/udev/net/link-config-gperf.gperf |  16 +--
+ 4 files changed, 90 insertions(+), 181 deletions(-)
+
+diff --git a/man/systemd.link.xml b/man/systemd.link.xml
+index fd744ebaed..dfb02073b2 100644
+--- a/man/systemd.link.xml
++++ b/man/systemd.link.xml
+@@ -710,58 +710,27 @@
+       </varlistentry>
+       <varlistentry>
+         <term><varname>RxChannels=</varname></term>
+-        <listitem>
+-          <para>Sets the number of receive channels (a number between 1 and 4294967295) .</para>
+-        </listitem>
+-      </varlistentry>
+-      <varlistentry>
+         <term><varname>TxChannels=</varname></term>
+-        <listitem>
+-          <para>Sets the number of transmit channels (a number between 1 and 4294967295).</para>
+-        </listitem>
+-      </varlistentry>
+-      <varlistentry>
+         <term><varname>OtherChannels=</varname></term>
+-        <listitem>
+-          <para>Sets the number of other channels (a number between 1 and 4294967295).</para>
+-        </listitem>
+-      </varlistentry>
+-      <varlistentry>
+         <term><varname>CombinedChannels=</varname></term>
+         <listitem>
+-          <para>Sets the number of combined set channels (a number between 1 and 4294967295).</para>
++          <para>Specifies the number of receive, transmit, other, or combined channels, respectively.
++          Takes an unsigned integer in the range 1…4294967295 or <literal>max</literal>. If set to
++          <literal>max</literal>, the advertised maximum value of the hardware will be used. When
++          unset, the number will not be changed. Defaults to unset.</para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term><varname>RxBufferSize=</varname></term>
+-        <listitem>
+-          <para>Takes an integer or <literal>max</literal>. Specifies the maximum number of pending packets
+-          in the NIC receive buffer. When unset, the kernel's default will be used. If set to
+-          <literal>max</literal>, the hardware's advertised maximum size will be used.</para>
+-        </listitem>
+-      </varlistentry>
+-      <varlistentry>
+         <term><varname>RxMiniBufferSize=</varname></term>
+-        <listitem>
+-          <para>Takes an integer or <literal>max</literal>. Specifies the maximum number of pending packets
+-          in the NIC mini receive buffer. When unset, the kernel's default will be used. If set to
+-          <literal>max</literal>, the hardware's advertised maximum size will be used.</para>
+-        </listitem>
+-      </varlistentry>
+-      <varlistentry>
+         <term><varname>RxJumboBufferSize=</varname></term>
+-        <listitem>
+-          <para>Takes an integer or <literal>max</literal>. Specifies the maximum number of pending packets
+-          in the NIC jumbo receive buffer. When unset, the kernel's default will be used. If set to
+-          <literal>max</literal>, the hardware's advertised maximum size will be used.</para>
+-        </listitem>
+-      </varlistentry>
+-      <varlistentry>
+         <term><varname>TxBufferSize=</varname></term>
+         <listitem>
+-          <para>Takes an integer or <literal>max</literal>. Specifies the maximum number of pending packets
+-          in the NIC transmit buffer. When unset, the kernel's default will be used. If set to
+-          <literal>max</literal>, the hardware's advertised maximum size will be used.</para>
++          <para>Specifies the maximum number of pending packets in the NIC receive buffer, mini receive
++          buffer, jumbo receive buffer, or transmit buffer, respectively. Takes an unsigned integer in
++          the range 1…4294967295 or <literal>max</literal>. If set to <literal>max</literal>, the
++          advertised maximum value of the hardware will be used. When unset, the number will not be
++          changed. Defaults to unset.</para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c
+index ed251ec8dd..2d41d861ba 100644
+--- a/src/shared/ethtool-util.c
++++ b/src/shared/ethtool-util.c
+@@ -329,6 +329,17 @@ int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct et
+                 dest = _v;                             \
+         } while(false)
+ 
++#define UPDATE_WITH_MAX(dest, max, val, updated)       \
++        do {                                           \
++                typeof(dest) _v = (val);               \
++                typeof(dest) _max = (max);             \
++                if (_v == 0 || _v > _max)              \
++                        _v = _max;                     \
++                if (dest != _v)                        \
++                        updated = true;                \
++                dest = _v;                             \
++        } while(false)
++
+ int ethtool_set_wol(int *ethtool_fd, const char *ifname, uint32_t wolopts) {
+         struct ethtool_wolinfo ecmd = {
+                 .cmd = ETHTOOL_GWOL,
+@@ -382,10 +393,10 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde
+         assert(ifname);
+         assert(ring);
+ 
+-        if (!ring->rx_pending_set &&
+-            !ring->rx_mini_pending_set &&
+-            !ring->rx_jumbo_pending_set &&
+-            !ring->tx_pending_set)
++        if (!ring->rx.set &&
++            !ring->rx_mini.set &&
++            !ring->rx_jumbo.set &&
++            !ring->tx.set)
+                 return 0;
+ 
+         r = ethtool_connect(ethtool_fd);
+@@ -398,25 +409,17 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde
+         if (r < 0)
+                 return -errno;
+ 
+-        if (ring->rx_pending_set)
+-                UPDATE(ecmd.rx_pending,
+-                       ring->rx_pending == 0 ? ecmd.rx_max_pending : ring->rx_pending,
+-                       need_update);
++        if (ring->rx.set)
++                UPDATE_WITH_MAX(ecmd.rx_pending, ecmd.rx_max_pending, ring->rx.value, need_update);
+ 
+-        if (ring->rx_mini_pending_set)
+-                UPDATE(ecmd.rx_mini_pending,
+-                       ring->rx_mini_pending == 0 ? ecmd.rx_mini_max_pending : ring->rx_mini_pending,
+-                       need_update);
++        if (ring->rx_mini.set)
++                UPDATE_WITH_MAX(ecmd.rx_mini_pending, ecmd.rx_mini_max_pending, ring->rx_mini.value, need_update);
+ 
+-        if (ring->rx_jumbo_pending_set)
+-                UPDATE(ecmd.rx_jumbo_pending,
+-                       ring->rx_jumbo_pending == 0 ? ecmd.rx_jumbo_max_pending : ring->rx_jumbo_pending,
+-                       need_update);
++        if (ring->rx_jumbo.set)
++                UPDATE_WITH_MAX(ecmd.rx_jumbo_pending, ecmd.rx_jumbo_max_pending, ring->rx_jumbo.value, need_update);
+ 
+-        if (ring->tx_pending_set)
+-                UPDATE(ecmd.tx_pending,
+-                       ring->tx_pending == 0 ? ecmd.tx_max_pending : ring->tx_pending,
+-                       need_update);
++        if (ring->tx.set)
++                UPDATE_WITH_MAX(ecmd.tx_pending, ecmd.tx_max_pending, ring->tx.value, need_update);
+ 
+         if (!need_update)
+                 return 0;
+@@ -832,10 +835,10 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha
+         assert(ifname);
+         assert(channels);
+ 
+-        if (!channels->rx_count_set &&
+-            !channels->tx_count_set &&
+-            !channels->other_count_set &&
+-            !channels->combined_count_set)
++        if (!channels->rx.set &&
++            !channels->tx.set &&
++            !channels->other.set &&
++            !channels->combined.set)
+                 return 0;
+ 
+         r = ethtool_connect(fd);
+@@ -848,17 +851,17 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha
+         if (r < 0)
+                 return -errno;
+ 
+-        if (channels->rx_count_set)
+-                UPDATE(ecmd.rx_count, channels->rx_count, need_update);
++        if (channels->rx.set)
++                UPDATE_WITH_MAX(ecmd.rx_count, ecmd.max_rx, channels->rx.value, need_update);
+ 
+-        if (channels->tx_count_set)
+-                UPDATE(ecmd.tx_count, channels->tx_count, need_update);
++        if (channels->tx.set)
++                UPDATE_WITH_MAX(ecmd.tx_count, ecmd.max_tx, channels->tx.value, need_update);
+ 
+-        if (channels->other_count_set)
+-                UPDATE(ecmd.other_count, channels->other_count, need_update);
++        if (channels->other.set)
++                UPDATE_WITH_MAX(ecmd.other_count, ecmd.max_other, channels->other.value, need_update);
+ 
+-        if (channels->combined_count_set)
+-                UPDATE(ecmd.combined_count, channels->combined_count, need_update);
++        if (channels->combined.set)
++                UPDATE_WITH_MAX(ecmd.combined_count, ecmd.max_combined, channels->combined.value, need_update);
+ 
+         if (!need_update)
+                 return 0;
+@@ -917,57 +920,6 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au
+         return 0;
+ }
+ 
+-int config_parse_channel(
+-                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) {
+-
+-        netdev_channels *channels = data;
+-        uint32_t k;
+-        int r;
+-
+-        assert(filename);
+-        assert(section);
+-        assert(lvalue);
+-        assert(rvalue);
+-        assert(data);
+-
+-        r = safe_atou32(rvalue, &k);
+-        if (r < 0) {
+-                log_syntax(unit, LOG_WARNING, filename, line, r,
+-                           "Failed to parse channel value for %s=, ignoring: %s", lvalue, rvalue);
+-                return 0;
+-        }
+-        if (k < 1) {
+-                log_syntax(unit, LOG_WARNING, filename, line, 0,
+-                           "Invalid %s= value, ignoring: %s", lvalue, rvalue);
+-                return 0;
+-        }
+-
+-        if (streq(lvalue, "RxChannels")) {
+-                channels->rx_count = k;
+-                channels->rx_count_set = true;
+-        } else if (streq(lvalue, "TxChannels")) {
+-                channels->tx_count = k;
+-                channels->tx_count_set = true;
+-        } else if (streq(lvalue, "OtherChannels")) {
+-                channels->other_count = k;
+-                channels->other_count_set = true;
+-        } else if (streq(lvalue, "CombinedChannels")) {
+-                channels->combined_count = k;
+-                channels->combined_count_set = true;
+-        }
+-
+-        return 0;
+-}
+-
+ int config_parse_advertise(
+                 const char *unit,
+                 const char *filename,
+@@ -1023,7 +975,7 @@ int config_parse_advertise(
+         }
+ }
+ 
+-int config_parse_nic_buffer_size(
++int config_parse_ring_buffer_or_channel(
+                 const char *unit,
+                 const char *filename,
+                 unsigned line,
+@@ -1035,7 +987,7 @@ int config_parse_nic_buffer_size(
+                 void *data,
+                 void *userdata) {
+ 
+-        netdev_ring_param *ring = data;
++        u32_opt *dst = data;
+         uint32_t k;
+         int r;
+ 
+@@ -1045,36 +997,32 @@ int config_parse_nic_buffer_size(
+         assert(rvalue);
+         assert(data);
+ 
+-        if (streq(rvalue, "max"))
+-                k = 0;
+-        else {
+-                r = safe_atou32(rvalue, &k);
+-                if (r < 0) {
+-                        log_syntax(unit, LOG_WARNING, filename, line, r,
+-                                "Failed to parse interface buffer value, ignoring: %s", rvalue);
+-                        return 0;
+-                }
+-                if (k < 1) {
+-                        log_syntax(unit, LOG_WARNING, filename, line, 0,
+-                                "Invalid %s= value, ignoring: %s", lvalue, rvalue);
+-                        return 0;
+-                }
++        if (isempty(rvalue)) {
++                dst->value = 0;
++                dst->set = false;
++                return 0;
++        }
++
++        if (streq(rvalue, "max")) {
++                dst->value = 0;
++                dst->set = true;
++                return 0;
+         }
+ 
+-        if (streq(lvalue, "RxBufferSize")) {
+-                ring->rx_pending = k;
+-                ring->rx_pending_set = true;
+-        } else if (streq(lvalue, "RxMiniBufferSize")) {
+-                ring->rx_mini_pending = k;
+-                ring->rx_mini_pending_set = true;
+-        } else if (streq(lvalue, "RxJumboBufferSize")) {
+-                ring->rx_jumbo_pending = k;
+-                ring->rx_jumbo_pending_set = true;
+-        } else if (streq(lvalue, "TxBufferSize")) {
+-                ring->tx_pending = k;
+-                ring->tx_pending_set = true;
++        r = safe_atou32(rvalue, &k);
++        if (r < 0) {
++                log_syntax(unit, LOG_WARNING, filename, line, r,
++                           "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
++                return 0;
++        }
++        if (k < 1) {
++                log_syntax(unit, LOG_WARNING, filename, line, 0,
++                           "Invalid %s= value, ignoring: %s", lvalue, rvalue);
++                return 0;
+         }
+ 
++        dst->value = k;
++        dst->set = true;
+         return 0;
+ }
+ 
+diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h
+index aea131914e..8fdbdec39a 100644
+--- a/src/shared/ethtool-util.h
++++ b/src/shared/ethtool-util.h
+@@ -57,30 +57,23 @@ struct ethtool_link_usettings {
+         } link_modes;
+ };
+ 
++typedef struct u32_opt {
++        uint32_t value; /* a value of 0 indicates the hardware advertised maximum should be used.*/
++        bool set;
++} u32_opt;
++
+ typedef struct netdev_channels {
+-        uint32_t rx_count;
+-        uint32_t tx_count;
+-        uint32_t other_count;
+-        uint32_t combined_count;
+-
+-        bool rx_count_set;
+-        bool tx_count_set;
+-        bool other_count_set;
+-        bool combined_count_set;
++        u32_opt rx;
++        u32_opt tx;
++        u32_opt other;
++        u32_opt combined;
+ } netdev_channels;
+ 
+ typedef struct netdev_ring_param {
+-        /* For any of the 4 following settings, a value of 0 indicates the hardware advertised maximum should
+-         * be used. */
+-        uint32_t rx_pending;
+-        uint32_t rx_mini_pending;
+-        uint32_t rx_jumbo_pending;
+-        uint32_t tx_pending;
+-
+-        bool rx_pending_set;
+-        bool rx_mini_pending_set;
+-        bool rx_jumbo_pending_set;
+-        bool tx_pending_set;
++        u32_opt rx;
++        u32_opt rx_mini;
++        u32_opt rx_jumbo;
++        u32_opt tx;
+ } netdev_ring_param;
+ 
+ int ethtool_get_driver(int *ethtool_fd, const char *ifname, char **ret);
+@@ -111,6 +104,5 @@ enum ethtool_link_mode_bit_indices ethtool_link_mode_bit_from_string(const char
+ CONFIG_PARSER_PROTOTYPE(config_parse_duplex);
+ CONFIG_PARSER_PROTOTYPE(config_parse_wol);
+ CONFIG_PARSER_PROTOTYPE(config_parse_port);
+-CONFIG_PARSER_PROTOTYPE(config_parse_channel);
+ CONFIG_PARSER_PROTOTYPE(config_parse_advertise);
+-CONFIG_PARSER_PROTOTYPE(config_parse_nic_buffer_size);
++CONFIG_PARSER_PROTOTYPE(config_parse_ring_buffer_or_channel);
+diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
+index e2f07d758b..d0190da5cb 100644
+--- a/src/udev/net/link-config-gperf.gperf
++++ b/src/udev/net/link-config-gperf.gperf
+@@ -58,15 +58,15 @@ Link.TCP6SegmentationOffload,          config_parse_tristate,                 0,
+ Link.UDPSegmentationOffload,           config_parse_warn_compat,              DISABLED_LEGACY,               0
+ Link.GenericReceiveOffload,            config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_GRO])
+ Link.LargeReceiveOffload,              config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_LRO])
+-Link.RxChannels,                       config_parse_channel,                  0,                             offsetof(LinkConfig, channels)
+-Link.TxChannels,                       config_parse_channel,                  0,                             offsetof(LinkConfig, channels)
+-Link.OtherChannels,                    config_parse_channel,                  0,                             offsetof(LinkConfig, channels)
+-Link.CombinedChannels,                 config_parse_channel,                  0,                             offsetof(LinkConfig, channels)
++Link.RxChannels,                       config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.rx)
++Link.TxChannels,                       config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.tx)
++Link.OtherChannels,                    config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.other)
++Link.CombinedChannels,                 config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.combined)
+ Link.Advertise,                        config_parse_advertise,                0,                             offsetof(LinkConfig, advertise)
+-Link.RxBufferSize,                     config_parse_nic_buffer_size,          0,                             offsetof(LinkConfig, ring)
+-Link.RxMiniBufferSize,                 config_parse_nic_buffer_size,          0,                             offsetof(LinkConfig, ring)
+-Link.RxJumboBufferSize,                config_parse_nic_buffer_size,          0,                             offsetof(LinkConfig, ring)
+-Link.TxBufferSize,                     config_parse_nic_buffer_size,          0,                             offsetof(LinkConfig, ring)
++Link.RxBufferSize,                     config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx)
++Link.RxMiniBufferSize,                 config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx_mini)
++Link.RxJumboBufferSize,                config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx_jumbo)
++Link.TxBufferSize,                     config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.tx)
+ Link.RxFlowControl,                    config_parse_tristate,                 0,                             offsetof(LinkConfig, rx_flow_control)
+ Link.TxFlowControl,                    config_parse_tristate,                 0,                             offsetof(LinkConfig, tx_flow_control)
+ Link.AutoNegotiationFlowControl,       config_parse_tristate,                 0,                             offsetof(LinkConfig, autoneg_flow_control)
+-- 
+2.31.1
+
diff --git a/SOURCES/20477.patch b/SOURCES/20477.patch
new file mode 100644
index 0000000..6676bff
--- /dev/null
+++ b/SOURCES/20477.patch
@@ -0,0 +1,561 @@
+From a1661a140c97a9e8fd90ee00f2de6baa214c9076 Mon Sep 17 00:00:00 2001
+From: Daan De Meyer <daan.j.demeyer@gmail.com>
+Date: Wed, 18 Aug 2021 13:52:00 +0100
+Subject: [PATCH] udev: Add support for configuring nic coalescing settings
+
+These are configured via the corresponding ethtool ioctl.
+---
+ man/systemd.link.xml                       |  71 +++++++
+ src/shared/ethtool-util.c                  | 205 +++++++++++++++++++++
+ src/shared/ethtool-util.h                  |  29 +++
+ src/udev/net/link-config-gperf.gperf       | 124 ++++++++-----
+ src/udev/net/link-config.c                 |   4 +
+ src/udev/net/link-config.h                 |   1 +
+ test/fuzz/fuzz-link-parser/directives.link |  22 +++
+ 7 files changed, 405 insertions(+), 51 deletions(-)
+
+diff --git a/man/systemd.link.xml b/man/systemd.link.xml
+index dfb02073b2..6d8dcb9af7 100644
+--- a/man/systemd.link.xml
++++ b/man/systemd.link.xml
+@@ -773,6 +773,77 @@
+           accept. An unsigned integer in the range 1…65535. Defaults to unset.</para>
+         </listitem>
+       </varlistentry>
++      <varlistentry>
++        <term><varname>UseAdaptiveRxCoalesce=</varname></term>
++        <term><varname>UseAdaptiveTxCoalesce=</varname></term>
++        <listitem>
++          <para>Boolean properties that, when set, enable/disable adaptive Rx/Tx coalescing if the hardware
++          supports it. When unset, the kernel's default will be used.</para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term><varname>RxCoalesceSec=</varname></term>
++        <term><varname>RxCoalesceIrqSec=</varname></term>
++        <term><varname>RxCoalesceLowSec=</varname></term>
++        <term><varname>RxCoalesceHighSec=</varname></term>
++        <term><varname>TxCoalesceSec=</varname></term>
++        <term><varname>TxCoalesceIrqSec=</varname></term>
++        <term><varname>TxCoalesceLowSec=</varname></term>
++        <term><varname>TxCoalesceHighSec=</varname></term>
++        <listitem>
++          <para>These properties configure the delay before Rx/Tx interrupts are generated after a packet is
++          sent/received. The <literal>Irq</literal> properties come into effect when the host is servicing an
++          IRQ. The <literal>Low</literal> and <literal>High</literal> properties come into effect when the
++          packet rate drops below the low packet rate threshold or exceeds the high packet rate threshold
++          respectively if adaptive Rx/Tx coalescing is enabled. When unset, the kernel's defaults will be
++          used.</para>
++        </listitem>
++      </varlistentry>
++        <varlistentry>
++        <term><varname>RxMaxCoalescedFrames=</varname></term>
++        <term><varname>RxMaxCoalescedIrqFrames=</varname></term>
++        <term><varname>RxMaxCoalescedLowFrames=</varname></term>
++        <term><varname>RxMaxCoalescedHighFrames=</varname></term>
++        <term><varname>TxMaxCoalescedFrames=</varname></term>
++        <term><varname>TxMaxCoalescedIrqFrames=</varname></term>
++        <term><varname>TxMaxCoalescedLowFrames=</varname></term>
++        <term><varname>TxMaxCoalescedHighFrames=</varname></term>
++        <listitem>
++          <para>These properties configure the maximum number of frames that are sent/received before a Rx/Tx
++          interrupt is generated. The <literal>Irq</literal> properties come into effect when the host is
++          servicing an IRQ. The <literal>Low</literal> and <literal>High</literal> properties come into
++          effect when the packet rate drops below the low packet rate threshold or exceeds the high packet
++          rate threshold respectively if adaptive Rx/Tx coalescing is enabled. When unset, the kernel's
++          defaults will be used.</para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term><varname>CoalescePacketRateLow=</varname></term>
++        <term><varname>CoalescePacketRateHigh=</varname></term>
++        <listitem>
++          <para>These properties configure the low and high packet rate (expressed in packets per second)
++          threshold respectively and are used to determine when the corresponding coalescing settings for low
++          and high packet rates come into effect if adaptive Rx/Tx coalescing is enabled. If unset, the
++          kernel's defaults will be used.</para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term><varname>CoalescePacketRateSampleIntervalSec=</varname></term>
++        <listitem>
++          <para>Configures how often to sample the packet rate used for adaptive Rx/Tx coalescing. This
++          property cannot be zero. This lowest time granularity supported by this property is seconds.
++          Partial seconds will be rounded up before being passed to the kernel. If unset, the kernel's
++          default will be used.</para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term><varname>StatisticsBlockCoalesceSec=</varname></term>
++        <listitem>
++          <para>How long to delay driver in-memory statistics block updates. If the driver does not have an
++          in-memory statistic block, this property is ignored. This property cannot be zero. If unset, the
++          kernel's default will be used.</para>
++        </listitem>
++      </varlistentry>
+ 
+     </variablelist>
+   </refsect1>
+diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c
+index 2d41d861ba..f7f553dd29 100644
+--- a/src/shared/ethtool-util.c
++++ b/src/shared/ethtool-util.c
+@@ -14,6 +14,7 @@
+ #include "memory-util.h"
+ #include "socket-util.h"
+ #include "string-table.h"
++#include "strv.h"
+ #include "strxcpyx.h"
+ 
+ static const char* const duplex_table[_DUP_MAX] = {
+@@ -1091,3 +1092,207 @@ int config_parse_wol(
+ 
+         return 0;
+ }
++
++int config_parse_coalesce_u32(
++                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) {
++        u32_opt *dst = data;
++        uint32_t k;
++        int r;
++
++        if (isempty(rvalue)) {
++                dst->value = 0;
++                dst->set = false;
++                return 0;
++        }
++
++        r = safe_atou32(rvalue, &k);
++        if (r < 0) {
++                log_syntax(unit, LOG_WARNING, filename, line, r,
++                           "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
++                return 0;
++        }
++
++        dst->value = k;
++        dst->set = true;
++        return 0;
++}
++
++int config_parse_coalesce_sec(
++                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) {
++        u32_opt *dst = data;
++        usec_t usec;
++        int r;
++
++        if (isempty(rvalue)) {
++                dst->value = 0;
++                dst->set = false;
++                return 0;
++        }
++
++        r = parse_sec(rvalue, &usec);
++        if (r < 0) {
++                log_syntax(unit, LOG_WARNING, filename, line, r,
++                           "Failed to parse coalesce setting value, ignoring: %s", rvalue);
++                return 0;
++        }
++
++        if (usec > UINT32_MAX) {
++                log_syntax(unit, LOG_WARNING, filename, line, 0,
++                           "Too large %s= value, ignoring: %s", lvalue, rvalue);
++                return 0;
++        }
++
++        if (STR_IN_SET(lvalue, "StatisticsBlockCoalesceSec", "CoalescePacketRateSampleIntervalSec") && usec < 1) {
++                log_syntax(unit, LOG_WARNING, filename, line, 0,
++                           "Invalid %s= value, ignoring: %s", lvalue, rvalue);
++                return 0;
++        }
++
++        dst->value = (uint32_t) usec;
++        dst->set = true;
++
++        return 0;
++}
++
++int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const netdev_coalesce_param *coalesce) {
++        struct ethtool_coalesce ecmd = {
++                .cmd = ETHTOOL_GCOALESCE,
++        };
++        struct ifreq ifr = {
++                .ifr_data = (void*) &ecmd,
++        };
++        bool need_update = false;
++        int r;
++
++        assert(ethtool_fd);
++        assert(ifname);
++        assert(coalesce);
++
++        if (coalesce->use_adaptive_rx_coalesce < 0 &&
++            coalesce->use_adaptive_tx_coalesce < 0 &&
++            !coalesce->rx_coalesce_usecs.set &&
++            !coalesce->rx_max_coalesced_frames.set &&
++            !coalesce->rx_coalesce_usecs_irq.set &&
++            !coalesce->rx_max_coalesced_frames_irq.set &&
++            !coalesce->tx_coalesce_usecs.set &&
++            !coalesce->tx_max_coalesced_frames.set &&
++            !coalesce->tx_coalesce_usecs_irq.set &&
++            !coalesce->tx_max_coalesced_frames_irq.set &&
++            !coalesce->stats_block_coalesce_usecs.set &&
++            !coalesce->pkt_rate_low.set &&
++            !coalesce->rx_coalesce_usecs_low.set &&
++            !coalesce->rx_max_coalesced_frames_low.set &&
++            !coalesce->tx_coalesce_usecs_low.set &&
++            !coalesce->tx_max_coalesced_frames_low.set &&
++            !coalesce->pkt_rate_high.set &&
++            !coalesce->rx_coalesce_usecs_high.set &&
++            !coalesce->rx_max_coalesced_frames_high.set &&
++            !coalesce->tx_coalesce_usecs_high.set &&
++            !coalesce->tx_max_coalesced_frames_high.set &&
++            !coalesce->rate_sample_interval.set)
++                return 0;
++
++        r = ethtool_connect(ethtool_fd);
++        if (r < 0)
++                return r;
++
++        strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
++
++        r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
++        if (r < 0)
++                return -errno;
++
++        if (coalesce->use_adaptive_rx_coalesce >= 0)
++                UPDATE(ecmd.use_adaptive_rx_coalesce, (uint32_t) coalesce->use_adaptive_rx_coalesce, need_update);
++
++        if (coalesce->use_adaptive_tx_coalesce >= 0)
++                UPDATE(ecmd.use_adaptive_tx_coalesce, (uint32_t) coalesce->use_adaptive_tx_coalesce, need_update);
++
++        if (coalesce->rx_coalesce_usecs.set)
++                UPDATE(ecmd.rx_coalesce_usecs, coalesce->rx_coalesce_usecs.value, need_update);
++
++        if (coalesce->rx_max_coalesced_frames.set)
++                UPDATE(ecmd.rx_max_coalesced_frames, coalesce->rx_max_coalesced_frames.value, need_update);
++
++        if (coalesce->rx_coalesce_usecs_irq.set)
++                UPDATE(ecmd.rx_coalesce_usecs_irq, coalesce->rx_coalesce_usecs_irq.value, need_update);
++
++        if (coalesce->rx_max_coalesced_frames_irq.set)
++                UPDATE(ecmd.rx_max_coalesced_frames_irq, coalesce->rx_max_coalesced_frames_irq.value, need_update);
++
++        if (coalesce->tx_coalesce_usecs.set)
++                UPDATE(ecmd.tx_coalesce_usecs, coalesce->tx_coalesce_usecs.value, need_update);
++
++        if (coalesce->tx_max_coalesced_frames.set)
++                UPDATE(ecmd.tx_max_coalesced_frames, coalesce->tx_max_coalesced_frames.value, need_update);
++
++        if (coalesce->tx_coalesce_usecs_irq.set)
++                UPDATE(ecmd.tx_coalesce_usecs_irq, coalesce->tx_coalesce_usecs_irq.value, need_update);
++
++        if (coalesce->tx_max_coalesced_frames_irq.set)
++                UPDATE(ecmd.tx_max_coalesced_frames_irq, coalesce->tx_max_coalesced_frames_irq.value, need_update);
++
++        if (coalesce->stats_block_coalesce_usecs.set)
++                UPDATE(ecmd.stats_block_coalesce_usecs, coalesce->stats_block_coalesce_usecs.value, need_update);
++
++        if (coalesce->pkt_rate_low.set)
++                UPDATE(ecmd.pkt_rate_low, coalesce->pkt_rate_low.value, need_update);
++
++        if (coalesce->rx_coalesce_usecs_low.set)
++                UPDATE(ecmd.rx_coalesce_usecs_low, coalesce->rx_coalesce_usecs_low.value, need_update);
++
++        if (coalesce->rx_max_coalesced_frames_low.set)
++                UPDATE(ecmd.rx_max_coalesced_frames_low, coalesce->rx_max_coalesced_frames_low.value, need_update);
++
++        if (coalesce->tx_coalesce_usecs_low.set)
++                UPDATE(ecmd.tx_coalesce_usecs_low, coalesce->tx_coalesce_usecs_low.value, need_update);
++
++        if (coalesce->tx_max_coalesced_frames_low.set)
++                UPDATE(ecmd.tx_max_coalesced_frames_low, coalesce->tx_max_coalesced_frames_low.value, need_update);
++
++        if (coalesce->pkt_rate_high.set)
++                UPDATE(ecmd.pkt_rate_high, coalesce->pkt_rate_high.value, need_update);
++
++        if (coalesce->rx_coalesce_usecs_high.set)
++                UPDATE(ecmd.rx_coalesce_usecs_high, coalesce->rx_coalesce_usecs_high.value, need_update);
++
++        if (coalesce->rx_max_coalesced_frames_high.set)
++                UPDATE(ecmd.rx_max_coalesced_frames_high, coalesce->rx_max_coalesced_frames_high.value, need_update);
++
++        if (coalesce->tx_coalesce_usecs_high.set)
++                UPDATE(ecmd.tx_coalesce_usecs_high, coalesce->tx_coalesce_usecs_high.value, need_update);
++
++        if (coalesce->tx_max_coalesced_frames_high.set)
++                UPDATE(ecmd.tx_max_coalesced_frames_high, coalesce->tx_max_coalesced_frames_high.value, need_update);
++
++        if (coalesce->rate_sample_interval.set)
++                UPDATE(ecmd.rate_sample_interval, DIV_ROUND_UP(coalesce->rate_sample_interval.value, USEC_PER_SEC), need_update);
++
++        if (!need_update)
++                return 0;
++
++        ecmd.cmd = ETHTOOL_SCOALESCE;
++        r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
++        if (r < 0)
++                return -errno;
++
++        return 0;
++}
+diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h
+index 8fdbdec39a..bb0333775c 100644
+--- a/src/shared/ethtool-util.h
++++ b/src/shared/ethtool-util.h
+@@ -76,6 +76,31 @@ typedef struct netdev_ring_param {
+         u32_opt tx;
+ } netdev_ring_param;
+ 
++typedef struct netdev_coalesce_param {
++        u32_opt rx_coalesce_usecs;
++        u32_opt rx_max_coalesced_frames;
++        u32_opt rx_coalesce_usecs_irq;
++        u32_opt rx_max_coalesced_frames_irq;
++        u32_opt tx_coalesce_usecs;
++        u32_opt tx_max_coalesced_frames;
++        u32_opt tx_coalesce_usecs_irq;
++        u32_opt tx_max_coalesced_frames_irq;
++        u32_opt stats_block_coalesce_usecs;
++        int use_adaptive_rx_coalesce;
++        int use_adaptive_tx_coalesce;
++        u32_opt pkt_rate_low;
++        u32_opt rx_coalesce_usecs_low;
++        u32_opt rx_max_coalesced_frames_low;
++        u32_opt tx_coalesce_usecs_low;
++        u32_opt tx_max_coalesced_frames_low;
++        u32_opt pkt_rate_high;
++        u32_opt rx_coalesce_usecs_high;
++        u32_opt rx_max_coalesced_frames_high;
++        u32_opt tx_coalesce_usecs_high;
++        u32_opt tx_max_coalesced_frames_high;
++        u32_opt rate_sample_interval;
++} netdev_coalesce_param;
++
+ int ethtool_get_driver(int *ethtool_fd, const char *ifname, char **ret);
+ int ethtool_get_link_info(int *ethtool_fd, const char *ifname,
+                           int *ret_autonegotiation, uint64_t *ret_speed,
+@@ -89,6 +114,7 @@ int ethtool_set_glinksettings(int *ethtool_fd, const char *ifname,
+                               uint64_t speed, Duplex duplex, NetDevPort port);
+ int ethtool_set_channels(int *ethtool_fd, const char *ifname, const netdev_channels *channels);
+ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg);
++int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const netdev_coalesce_param *coalesce);
+ 
+ const char *duplex_to_string(Duplex d) _const_;
+ Duplex duplex_from_string(const char *d) _pure_;
+@@ -106,3 +132,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wol);
+ CONFIG_PARSER_PROTOTYPE(config_parse_port);
+ CONFIG_PARSER_PROTOTYPE(config_parse_advertise);
+ CONFIG_PARSER_PROTOTYPE(config_parse_ring_buffer_or_channel);
++CONFIG_PARSER_PROTOTYPE(config_parse_coalesce_u32);
++CONFIG_PARSER_PROTOTYPE(config_parse_coalesce_sec);
++CONFIG_PARSER_PROTOTYPE(config_parse_nic_coalesce_setting);
+diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
+index d0190da5cb..f800de8386 100644
+--- a/src/udev/net/link-config-gperf.gperf
++++ b/src/udev/net/link-config-gperf.gperf
+@@ -21,54 +21,76 @@ struct ConfigPerfItem;
+ %struct-type
+ %includes
+ %%
+-Match.MACAddress,                      config_parse_hwaddrs,                  0,                             offsetof(LinkConfig, match.mac)
+-Match.PermanentMACAddress,             config_parse_hwaddrs,                  0,                             offsetof(LinkConfig, match.permanent_mac)
+-Match.OriginalName,                    config_parse_match_ifnames,            0,                             offsetof(LinkConfig, match.ifname)
+-Match.Path,                            config_parse_match_strv,               0,                             offsetof(LinkConfig, match.path)
+-Match.Driver,                          config_parse_match_strv,               0,                             offsetof(LinkConfig, match.driver)
+-Match.Type,                            config_parse_match_strv,               0,                             offsetof(LinkConfig, match.iftype)
+-Match.Property,                        config_parse_match_property,           0,                             offsetof(LinkConfig, match.property)
+-Match.Host,                            config_parse_net_condition,            CONDITION_HOST,                offsetof(LinkConfig, conditions)
+-Match.Virtualization,                  config_parse_net_condition,            CONDITION_VIRTUALIZATION,      offsetof(LinkConfig, conditions)
+-Match.KernelCommandLine,               config_parse_net_condition,            CONDITION_KERNEL_COMMAND_LINE, offsetof(LinkConfig, conditions)
+-Match.KernelVersion,                   config_parse_net_condition,            CONDITION_KERNEL_VERSION,      offsetof(LinkConfig, conditions)
+-Match.Architecture,                    config_parse_net_condition,            CONDITION_ARCHITECTURE,        offsetof(LinkConfig, conditions)
+-Link.Description,                      config_parse_string,                   0,                             offsetof(LinkConfig, description)
+-Link.MACAddressPolicy,                 config_parse_mac_address_policy,       0,                             offsetof(LinkConfig, mac_address_policy)
+-Link.MACAddress,                       config_parse_hwaddr,                   0,                             offsetof(LinkConfig, mac)
+-Link.NamePolicy,                       config_parse_name_policy,              0,                             offsetof(LinkConfig, name_policy)
+-Link.Name,                             config_parse_ifname,                   0,                             offsetof(LinkConfig, name)
+-Link.AlternativeName,                  config_parse_ifnames,                  IFNAME_VALID_ALTERNATIVE,      offsetof(LinkConfig, alternative_names)
+-Link.AlternativeNamesPolicy,           config_parse_alternative_names_policy, 0,                             offsetof(LinkConfig, alternative_names_policy)
+-Link.Alias,                            config_parse_ifalias,                  0,                             offsetof(LinkConfig, alias)
+-Link.TransmitQueues,                   config_parse_rx_tx_queues,             0,                             offsetof(LinkConfig, txqueues)
+-Link.ReceiveQueues,                    config_parse_rx_tx_queues,             0,                             offsetof(LinkConfig, rxqueues)
+-Link.TransmitQueueLength,              config_parse_txqueuelen,               0,                             offsetof(LinkConfig, txqueuelen)
+-Link.MTUBytes,                         config_parse_mtu,                      AF_UNSPEC,                     offsetof(LinkConfig, mtu)
+-Link.BitsPerSecond,                    config_parse_si_uint64,                0,                             offsetof(LinkConfig, speed)
+-Link.Duplex,                           config_parse_duplex,                   0,                             offsetof(LinkConfig, duplex)
+-Link.AutoNegotiation,                  config_parse_tristate,                 0,                             offsetof(LinkConfig, autonegotiation)
+-Link.WakeOnLan,                        config_parse_wol,                      0,                             offsetof(LinkConfig, wol)
+-Link.Port,                             config_parse_port,                     0,                             offsetof(LinkConfig, port)
+-Link.ReceiveChecksumOffload,           config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_RX])
+-Link.TransmitChecksumOffload,          config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_TX])
+-Link.GenericSegmentationOffload,       config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_GSO])
+-Link.TCPSegmentationOffload,           config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_TSO])
+-Link.TCP6SegmentationOffload,          config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_TSO6])
+-Link.UDPSegmentationOffload,           config_parse_warn_compat,              DISABLED_LEGACY,               0
+-Link.GenericReceiveOffload,            config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_GRO])
+-Link.LargeReceiveOffload,              config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_LRO])
+-Link.RxChannels,                       config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.rx)
+-Link.TxChannels,                       config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.tx)
+-Link.OtherChannels,                    config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.other)
+-Link.CombinedChannels,                 config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.combined)
+-Link.Advertise,                        config_parse_advertise,                0,                             offsetof(LinkConfig, advertise)
+-Link.RxBufferSize,                     config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx)
+-Link.RxMiniBufferSize,                 config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx_mini)
+-Link.RxJumboBufferSize,                config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx_jumbo)
+-Link.TxBufferSize,                     config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.tx)
+-Link.RxFlowControl,                    config_parse_tristate,                 0,                             offsetof(LinkConfig, rx_flow_control)
+-Link.TxFlowControl,                    config_parse_tristate,                 0,                             offsetof(LinkConfig, tx_flow_control)
+-Link.AutoNegotiationFlowControl,       config_parse_tristate,                 0,                             offsetof(LinkConfig, autoneg_flow_control)
+-Link.GenericSegmentOffloadMaxBytes,    config_parse_iec_size,                 0,                             offsetof(LinkConfig, gso_max_size)
+-Link.GenericSegmentOffloadMaxSegments, config_parse_uint32,                   0,                             offsetof(LinkConfig, gso_max_segments)
++Match.MACAddress,                         config_parse_hwaddrs,                  0,                             offsetof(LinkConfig, match.mac)
++Match.PermanentMACAddress,                config_parse_hwaddrs,                  0,                             offsetof(LinkConfig, match.permanent_mac)
++Match.OriginalName,                       config_parse_match_ifnames,            0,                             offsetof(LinkConfig, match.ifname)
++Match.Path,                               config_parse_match_strv,               0,                             offsetof(LinkConfig, match.path)
++Match.Driver,                             config_parse_match_strv,               0,                             offsetof(LinkConfig, match.driver)
++Match.Type,                               config_parse_match_strv,               0,                             offsetof(LinkConfig, match.iftype)
++Match.Property,                           config_parse_match_property,           0,                             offsetof(LinkConfig, match.property)
++Match.Host,                               config_parse_net_condition,            CONDITION_HOST,                offsetof(LinkConfig, conditions)
++Match.Virtualization,                     config_parse_net_condition,            CONDITION_VIRTUALIZATION,      offsetof(LinkConfig, conditions)
++Match.KernelCommandLine,                  config_parse_net_condition,            CONDITION_KERNEL_COMMAND_LINE, offsetof(LinkConfig, conditions)
++Match.KernelVersion,                      config_parse_net_condition,            CONDITION_KERNEL_VERSION,      offsetof(LinkConfig, conditions)
++Match.Architecture,                       config_parse_net_condition,            CONDITION_ARCHITECTURE,        offsetof(LinkConfig, conditions)
++Link.Description,                         config_parse_string,                   0,                             offsetof(LinkConfig, description)
++Link.MACAddressPolicy,                    config_parse_mac_address_policy,       0,                             offsetof(LinkConfig, mac_address_policy)
++Link.MACAddress,                          config_parse_hwaddr,                   0,                             offsetof(LinkConfig, mac)
++Link.NamePolicy,                          config_parse_name_policy,              0,                             offsetof(LinkConfig, name_policy)
++Link.Name,                                config_parse_ifname,                   0,                             offsetof(LinkConfig, name)
++Link.AlternativeName,                     config_parse_ifnames,                  IFNAME_VALID_ALTERNATIVE,      offsetof(LinkConfig, alternative_names)
++Link.AlternativeNamesPolicy,              config_parse_alternative_names_policy, 0,                             offsetof(LinkConfig, alternative_names_policy)
++Link.Alias,                               config_parse_ifalias,                  0,                             offsetof(LinkConfig, alias)
++Link.TransmitQueues,                      config_parse_rx_tx_queues,             0,                             offsetof(LinkConfig, txqueues)
++Link.ReceiveQueues,                       config_parse_rx_tx_queues,             0,                             offsetof(LinkConfig, rxqueues)
++Link.TransmitQueueLength,                 config_parse_txqueuelen,               0,                             offsetof(LinkConfig, txqueuelen)
++Link.MTUBytes,                            config_parse_mtu,                      AF_UNSPEC,                     offsetof(LinkConfig, mtu)
++Link.BitsPerSecond,                       config_parse_si_uint64,                0,                             offsetof(LinkConfig, speed)
++Link.Duplex,                              config_parse_duplex,                   0,                             offsetof(LinkConfig, duplex)
++Link.AutoNegotiation,                     config_parse_tristate,                 0,                             offsetof(LinkConfig, autonegotiation)
++Link.WakeOnLan,                           config_parse_wol,                      0,                             offsetof(LinkConfig, wol)
++Link.Port,                                config_parse_port,                     0,                             offsetof(LinkConfig, port)
++Link.ReceiveChecksumOffload,              config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_RX])
++Link.TransmitChecksumOffload,             config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_TX])
++Link.GenericSegmentationOffload,          config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_GSO])
++Link.TCPSegmentationOffload,              config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_TSO])
++Link.TCP6SegmentationOffload,             config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_TSO6])
++Link.UDPSegmentationOffload,              config_parse_warn_compat,              DISABLED_LEGACY,               0
++Link.GenericReceiveOffload,               config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_GRO])
++Link.LargeReceiveOffload,                 config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_LRO])
++Link.RxChannels,                          config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.rx)
++Link.TxChannels,                          config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.tx)
++Link.OtherChannels,                       config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.other)
++Link.CombinedChannels,                    config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.combined)
++Link.Advertise,                           config_parse_advertise,                0,                             offsetof(LinkConfig, advertise)
++Link.RxBufferSize,                        config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx)
++Link.RxMiniBufferSize,                    config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx_mini)
++Link.RxJumboBufferSize,                   config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.rx_jumbo)
++Link.TxBufferSize,                        config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, ring.tx)
++Link.RxFlowControl,                       config_parse_tristate,                 0,                             offsetof(LinkConfig, rx_flow_control)
++Link.TxFlowControl,                       config_parse_tristate,                 0,                             offsetof(LinkConfig, tx_flow_control)
++Link.AutoNegotiationFlowControl,          config_parse_tristate,                 0,                             offsetof(LinkConfig, autoneg_flow_control)
++Link.GenericSegmentOffloadMaxBytes,       config_parse_iec_size,                 0,                             offsetof(LinkConfig, gso_max_size)
++Link.GenericSegmentOffloadMaxSegments,    config_parse_uint32,                   0,                             offsetof(LinkConfig, gso_max_segments)
++Link.RxCoalesceSec,                       config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.rx_coalesce_usecs)
++Link.RxMaxCoalescedFrames,                config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.rx_max_coalesced_frames)
++Link.RxCoalesceIrqSec,                    config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.rx_coalesce_usecs_irq)
++Link.RxMaxCoalescedIrqFrames,             config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.rx_max_coalesced_frames_irq)
++Link.TxCoalesceSec,                       config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.tx_coalesce_usecs)
++Link.TxMaxCoalescedFrames,                config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.tx_max_coalesced_frames)
++Link.TxCoalesceIrqSec,                    config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.tx_coalesce_usecs_irq)
++Link.TxMaxCoalescedIrqFrames,             config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_irq)
++Link.StatisticsBlockCoalesceSec,          config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.stats_block_coalesce_usecs)
++Link.UseAdaptiveRxCoalesce,               config_parse_tristate,                 0,                             offsetof(LinkConfig, coalesce.use_adaptive_rx_coalesce)
++Link.UseAdaptiveTxCoalesce,               config_parse_tristate,                 0,                             offsetof(LinkConfig, coalesce.use_adaptive_tx_coalesce)
++Link.CoalescePacketRateLow,               config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.pkt_rate_low)
++Link.RxCoalesceLowSec,                    config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.rx_coalesce_usecs_low)
++Link.RxMaxCoalescedLowFrames,             config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.rx_max_coalesced_frames_low)
++Link.TxCoalesceLowSec,                    config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.tx_coalesce_usecs_low)
++Link.TxMaxCoalescedLowFrames,             config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_low)
++Link.CoalescePacketRateHigh,              config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.pkt_rate_high)
++Link.RxCoalesceHighSec,                   config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.rx_coalesce_usecs_high)
++Link.RxMaxCoalescedHighFrames,            config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.rx_max_coalesced_frames_high)
++Link.TxCoalesceHighSec,                   config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.tx_coalesce_usecs_high)
++Link.TxMaxCoalescedHighFrames,            config_parse_coalesce_u32,             0,                             offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_high)
++Link.CoalescePacketRateSampleIntervalSec, config_parse_coalesce_sec,             0,                             offsetof(LinkConfig, coalesce.rate_sample_interval)
+diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
+index 8dfe23691b..9451bd8b66 100644
+--- a/src/udev/net/link-config.c
++++ b/src/udev/net/link-config.c
+@@ -353,6 +353,10 @@ static int link_config_apply_ethtool_settings(int *ethtool_fd, const LinkConfig
+         if (r < 0)
+                 log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m");
+ 
++        r = ethtool_set_nic_coalesce_settings(ethtool_fd, name, &config->coalesce);
++        if (r < 0)
++                log_device_warning_errno(device, r, "Could not set coalesce settings, ignoring: %m");
++
+         return 0;
+ }
+ 
+diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
+index b505c94f95..8a29a92822 100644
+--- a/src/udev/net/link-config.h
++++ b/src/udev/net/link-config.h
+@@ -64,6 +64,7 @@ struct LinkConfig {
+         int rx_flow_control;
+         int tx_flow_control;
+         int autoneg_flow_control;
++        netdev_coalesce_param coalesce;
+ 
+         LIST_FIELDS(LinkConfig, links);
+ };
+diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link
+index 112a81930f..5f232ce698 100644
+--- a/test/fuzz/fuzz-link-parser/directives.link
++++ b/test/fuzz/fuzz-link-parser/directives.link
+@@ -51,3 +51,25 @@ TxFlowControl=
+ AutoNegotiationFlowControl=
+ GenericSegmentOffloadMaxBytes=
+ GenericSegmentOffloadMaxSegments=
++RxCoalesceSec=
++RxMaxCoalescedFrames=
++RxCoalesceIrqSec=
++RxMaxCoalescedIrqFrames=
++TxCoalesceSec=
++TxMaxCoalescedFrames=
++TxCoalesceIrqSec=
++TxMaxCoalescedIrqFrames=
++StatisticsBlockCoalesceSec=
++UseAdaptiveRxCoalesce=
++UseAdaptiveTxCoalesce=
++CoalescePacketRateLow=
++RxCoalesceLowSec=
++RxMaxCoalescedLowFrames=
++TxCoalesceLowSec=
++TxMaxCoalescedLowFrames=
++CoalescePacketRateHigh=
++RxCoalesceHighSec=
++RxMaxCoalescedHighFrames=
++TxCoalesceHighSec=
++TxMaxCoalescedHighFrames=
++CoalescePacketRateSampleIntervalSec=
+-- 
+2.31.1
+
diff --git a/SOURCES/20484.patch b/SOURCES/20484.patch
new file mode 100644
index 0000000..9da073b
--- /dev/null
+++ b/SOURCES/20484.patch
@@ -0,0 +1,96 @@
+From 0e5c20b7a4f47fd3f8edbc2735810ea3513360bb Mon Sep 17 00:00:00 2001
+From: Daan De Meyer <daan.j.demeyer@gmail.com>
+Date: Thu, 19 Aug 2021 13:44:35 +0100
+Subject: [PATCH] link: Add support for rx-gro-hw nic feature
+
+---
+ man/systemd.link.xml                       |  7 +++++++
+ src/shared/ethtool-util.c                  | 15 ++++++++-------
+ src/shared/ethtool-util.h                  |  1 +
+ src/udev/net/link-config-gperf.gperf       |  1 +
+ test/fuzz/fuzz-link-parser/directives.link |  1 +
+ 5 files changed, 18 insertions(+), 7 deletions(-)
+
+diff --git a/man/systemd.link.xml b/man/systemd.link.xml
+index 6d8dcb9af7..638a1522cd 100644
+--- a/man/systemd.link.xml
++++ b/man/systemd.link.xml
+@@ -701,6 +701,13 @@
+           When unset, the kernel's default will be used.</para>
+         </listitem>
+       </varlistentry>
++      <varlistentry>
++        <term><varname>GenericReceiveOffloadHardware=</varname></term>
++        <listitem>
++          <para>Takes a boolean. If set to true, hardware accelerated Generic Receive Offload (GRO) is
++          enabled. When unset, the kernel's default will be used.</para>
++        </listitem>
++      </varlistentry>
+       <varlistentry>
+         <term><varname>LargeReceiveOffload=</varname></term>
+         <listitem>
+diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c
+index f7f553dd29..a08bb2b7f5 100644
+--- a/src/shared/ethtool-util.c
++++ b/src/shared/ethtool-util.c
+@@ -70,13 +70,14 @@ DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort);
+ DEFINE_CONFIG_PARSE_ENUM(config_parse_port, port, NetDevPort, "Failed to parse Port setting");
+ 
+ static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
+-        [NET_DEV_FEAT_RX]   = "rx-checksum",
+-        [NET_DEV_FEAT_TX]   = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */
+-        [NET_DEV_FEAT_GSO]  = "tx-generic-segmentation",
+-        [NET_DEV_FEAT_GRO]  = "rx-gro",
+-        [NET_DEV_FEAT_LRO]  = "rx-lro",
+-        [NET_DEV_FEAT_TSO]  = "tx-tcp-segmentation",
+-        [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation",
++        [NET_DEV_FEAT_RX]     = "rx-checksum",
++        [NET_DEV_FEAT_TX]     = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */
++        [NET_DEV_FEAT_GSO]    = "tx-generic-segmentation",
++        [NET_DEV_FEAT_GRO]    = "rx-gro",
++        [NET_DEV_FEAT_GRO_HW] = "rx-gro-hw",
++        [NET_DEV_FEAT_LRO]    = "rx-lro",
++        [NET_DEV_FEAT_TSO]    = "tx-tcp-segmentation",
++        [NET_DEV_FEAT_TSO6]   = "tx-tcp6-segmentation",
+ };
+ 
+ static const char* const ethtool_link_mode_bit_table[] = {
+diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h
+index bb0333775c..2181ab6fd6 100644
+--- a/src/shared/ethtool-util.h
++++ b/src/shared/ethtool-util.h
+@@ -23,6 +23,7 @@ typedef enum NetDevFeature {
+         NET_DEV_FEAT_TX,
+         NET_DEV_FEAT_GSO,
+         NET_DEV_FEAT_GRO,
++        NET_DEV_FEAT_GRO_HW,
+         NET_DEV_FEAT_LRO,
+         NET_DEV_FEAT_TSO,
+         NET_DEV_FEAT_TSO6,
+diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
+index f800de8386..44b46cb17c 100644
+--- a/src/udev/net/link-config-gperf.gperf
++++ b/src/udev/net/link-config-gperf.gperf
+@@ -57,6 +57,7 @@ Link.TCPSegmentationOffload,              config_parse_tristate,
+ Link.TCP6SegmentationOffload,             config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_TSO6])
+ Link.UDPSegmentationOffload,              config_parse_warn_compat,              DISABLED_LEGACY,               0
+ Link.GenericReceiveOffload,               config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_GRO])
++Link.GenericReceiveOffloadHardware,       config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_GRO_HW])
+ Link.LargeReceiveOffload,                 config_parse_tristate,                 0,                             offsetof(LinkConfig, features[NET_DEV_FEAT_LRO])
+ Link.RxChannels,                          config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.rx)
+ Link.TxChannels,                          config_parse_ring_buffer_or_channel,   0,                             offsetof(LinkConfig, channels.tx)
+diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link
+index 5f232ce698..b5cffb1a27 100644
+--- a/test/fuzz/fuzz-link-parser/directives.link
++++ b/test/fuzz/fuzz-link-parser/directives.link
+@@ -36,6 +36,7 @@ TCPSegmentationOffload=
+ TCP6SegmentationOffload=
+ UDPSegmentationOffload=
+ GenericReceiveOffload=
++GenericReceiveOffloadHardware=
+ LargeReceiveOffload=
+ RxChannels=
+ TxChannels=
+-- 
+2.31.1
+
diff --git a/SOURCES/20743.patch b/SOURCES/20743.patch
new file mode 100644
index 0000000..0975ce8
--- /dev/null
+++ b/SOURCES/20743.patch
@@ -0,0 +1,41 @@
+From 0fc51b569570e8bf5aecd5ee03a88eb668b7b385 Mon Sep 17 00:00:00 2001
+From: Anita Zhang <the.anitazha@gmail.com>
+Date: Tue, 14 Sep 2021 16:33:10 -0700
+Subject: [PATCH] fileio: start with 4k buffer for procfs
+
+There's a very gradual increase of anonymous memory in systemd-journald that
+blames to 2ac67221bb6270f0fbe7cbd0076653832cd49de2.
+
+systemd-journald makes many calls to read /proc/PID/cmdline and
+/proc/PID/status, both of which tend to be well under 4K. However the
+combination of allocating 4M read buffers, then using `realloc()` to
+shrink the buffer in `read_virtual_file()` appears to be creating
+fragmentation in the heap (when combined with the other allocations
+systemd-journald is doing).
+
+To help mitigate this, try reading /proc with a 4K buffer as
+`read_virtual_file()` did before 2ac67221bb6270f0fbe7cbd0076653832cd49de2.
+If it isn't big enough then try again with the larger buffers.
+---
+ src/basic/fileio.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/basic/fileio.c b/src/basic/fileio.c
+index 99a44fdea2..466c6321c7 100644
+--- a/src/basic/fileio.c
++++ b/src/basic/fileio.c
+@@ -431,6 +431,11 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
+                         }
+ 
+                         n_retries--;
++                } else if (n_retries > 1) {
++                        /* Files in /proc are generally smaller than the page size so let's start with a page size
++                         * buffer from malloc and only use the max buffer on the final try. */
++                        size = MIN3(page_size() - 1, READ_VIRTUAL_BYTES_MAX, max_size);
++                        n_retries = 1;
+                 } else {
+                         size = MIN(READ_VIRTUAL_BYTES_MAX, max_size);
+                         n_retries = 0;
+-- 
+2.31.1
+
diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec
index 50d30d2..6190ee9 100644
--- a/SPECS/systemd.spec
+++ b/SPECS/systemd.spec
@@ -39,8 +39,8 @@
 Name:           systemd
 Url:            https://www.freedesktop.org/wiki/Software/systemd
 %if %{without inplace}
-Version:        249.2
-Release:        1.2%{?dist}
+Version:        249.4
+Release:        1.1%{?dist}
 %else
 # determine the build information from local checkout
 Version:        %(tools/meson-vcs-tag.sh . error | sed -r 's/-([0-9])/.^\1/; s/-g/_g/')
@@ -108,6 +108,11 @@ Patch0001:      18621-fb.patch
 # PR 18621: Quiet "proc: Bad value for 'hidepid'" messages
 Patch0001:      https://github.com/systemd/systemd/pull/18621.patch
 %endif
+Patch0002:      https://github.com/systemd/systemd/pull/20743.patch
+Patch0003:      https://github.com/systemd/systemd/pull/20458.patch
+Patch0004:      https://github.com/systemd/systemd/pull/20472.patch
+Patch0005:      https://github.com/systemd/systemd/pull/20477.patch
+Patch0006:      https://github.com/systemd/systemd/pull/20484.patch
 
 # Downstream-only patches (0500–9999)
 
@@ -1054,6 +1059,11 @@ fi
 %endif
 
 %changelog
+* Mon Sep 20 2021 Anita Zhang <the.anitazha@gmail.com> - 249.4-1.1
+- New stable point release
+- Backport optimization for read_virtual_file() (#20743)
+- Backport new features for systemd-networkd (#20743, #20472, #20477, #20484)
+
 * Thu Jul 29 2021 Anita Zhang <the.anitazha@gmail.com> - 249.2-1.2
 - Remove Obsoletes lines on systemd-resolved and systemd-networkd since we don't
   want to install these by default.