Compare commits
43 Commits
57680ddd40
...
bba1f90ff5
Author | SHA1 | Date |
---|---|---|
Yu Watanabe | bba1f90ff5 | |
Yu Watanabe | a34811e4ef | |
Susant Sahani | 5d3b801764 | |
Yu Watanabe | d739fddeb5 | |
Susant Sahani | cd305af1fe | |
Jörg Thalheim | eec394f10b | |
Chris Down | 0d14eefb0d | |
Chris Down | a1e13c30de | |
Chris Down | 5bb67b107f | |
Chris Down | dfb3303b6c | |
Benjamin Berg | b7cf4b4ef5 | |
Benjamin Berg | 5b058473fe | |
Benjamin Berg | 96b10a13f2 | |
Benjamin Berg | 39f7d10c24 | |
Benjamin Berg | 2909f4dd28 | |
Benjamin Berg | cccf570355 | |
Christian Göttsche | 257188f80c | |
Christian Göttsche | 61f3e897f1 | |
Yu Watanabe | f6c6af3811 | |
Susant Sahani | ad8352f4ff | |
Susant Sahani | aa550d2a51 | |
Yu Watanabe | f2c5c1296a | |
Susant Sahani | 982998b087 | |
Yu Watanabe | 95edcf3fac | |
Susant Sahani | 609e8340bb | |
Yu Watanabe | bc0769c9f7 | |
Susant Sahani | a74760653c | |
Yu Watanabe | f1de1eb3e3 | |
Yu Watanabe | 19f86a6351 | |
Yu Watanabe | 4666f63bb8 | |
Yu Watanabe | 0ebb76de8b | |
Yu Watanabe | 34658df256 | |
Yu Watanabe | 931c8c824a | |
Yu Watanabe | b934ac3d6e | |
Yu Watanabe | 2a09633117 | |
Yu Watanabe | 3c874fd79d | |
Susant Sahani | a781ddefe5 | |
Susant Sahani | bd6379ec57 | |
Susant Sahani | 34332af2bc | |
Susant Sahani | 5ead535224 | |
Susant Sahani | 3efdd6af2c | |
Susant Sahani | a32c7a4615 | |
Susant Sahani | 90867f6a3a |
|
@ -267,6 +267,14 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
|
|||
Takes interface name or index number.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<command>forcerenew</command>
|
||||
</term>
|
||||
<listitem><para>Send a FORCERENEW message to all connected clients, triggering DHCP reconfiguration.
|
||||
Takes interface name or index number.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<command>reconfigure</command>
|
||||
|
|
|
@ -61,6 +61,15 @@
|
|||
<listitem><para>Specifies the time interval to calculate the traffic speed of each interface.
|
||||
If <varname>SpeedMeter=no</varname>, the value is ignored. Defaults to 10sec.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ManageForeignRoutes=</varname></term>
|
||||
<listitem><para>A boolean. When true, <command>systemd-networkd</command> will store any routes
|
||||
configured by other tools in its memory. When false, <command>systemd-networkd</command> will
|
||||
not manage the foreign routes, thus they are kept even if <varname>KeepConfiguration=</varname>
|
||||
is false. Defaults to yes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -193,11 +193,17 @@
|
|||
<varlistentry>
|
||||
<term><varname>DNSOverTLS=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean argument or <literal>opportunistic</literal>.
|
||||
If true all connections to the server will be encrypted. Note that
|
||||
this mode requires a DNS server that supports DNS-over-TLS and has
|
||||
a valid certificate for it's IP. If the DNS server does not support
|
||||
DNS-over-TLS all DNS requests will fail. When set to <literal>opportunistic</literal>
|
||||
<para>Takes a boolean argument or <literal>opportunistic</literal>. If
|
||||
true all connections to the server will be encrypted. Note that this
|
||||
mode requires a DNS server that supports DNS-over-TLS and has a valid
|
||||
certificate. If the hostname was specified in <varname>DNS=</varname>
|
||||
by using the format format <literal>address#server_name</literal> it
|
||||
is used to validate its certificate and also to enable Server Name
|
||||
Indication (SNI) when opening a TLS connection. Otherwise
|
||||
the certificate is checked against the server's IP.
|
||||
If the DNS server does not support DNS-over-TLS all DNS requests will fail.</para>
|
||||
|
||||
<para>When set to <literal>opportunistic</literal>
|
||||
DNS request are attempted to send encrypted with DNS-over-TLS.
|
||||
If the DNS server does not support TLS, DNS-over-TLS is disabled.
|
||||
Note that this mode makes DNS-over-TLS vulnerable to "downgrade"
|
||||
|
@ -214,9 +220,6 @@
|
|||
resolver is not capable of authenticating the server, so it is
|
||||
vulnerable to "man-in-the-middle" attacks.</para>
|
||||
|
||||
<para>Server Name Indication (SNI) can be used when opening a TLS connection.
|
||||
Entries in <varname>DNS=</varname> should be in format <literal>address#server_name</literal>.</para>
|
||||
|
||||
<para>In addition to this global DNSOverTLS setting
|
||||
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
also maintains per-link DNSOverTLS settings. For system DNS
|
||||
|
|
|
@ -700,6 +700,30 @@
|
|||
<para>Takes a integer. Specifies the NIC transmit ring buffer size. When unset, the kernel's default will be used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>RxFlowControl=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean. When set, enables the receive flow control, also known as the ethernet
|
||||
receive PAUSE message (generate and send ethernet PAUSE frames). When unset, the kernel's
|
||||
default will be used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>TxFlowControl=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean. When set, enables the transmit flow control, also known as the ethernet
|
||||
transmit PAUSE message (respond to received ethernet PAUSE frames). When unset, the kernel's
|
||||
default will be used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>AutoNegotiationFlowControl=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean. When set, the auto negotiation enables the interface to exchange state
|
||||
advertisements with the connected peer so that the two devices can agree on the ethernet
|
||||
PAUSE configuration. When unset, the kernel's default will be used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
|
|
@ -1694,6 +1694,14 @@
|
|||
a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1-128. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>WithoutRA=</varname></term>
|
||||
<listitem>
|
||||
<para>When true, DHCPv6 client starts without router advertisements's managed or other address configuration flag.
|
||||
Defaults to false.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -1768,6 +1776,14 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>DHCPv6Client=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean. When true (the default), the DHCPv6 client will be started when the
|
||||
RA has the managed or other information flag.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -2038,6 +2054,11 @@
|
|||
to 2592000 seconds (30 days).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Assign=</varname></term>
|
||||
<listitem><para>Takes a boolean. When true, adds an address from the prefix. Default to false.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -2327,7 +2348,9 @@
|
|||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -2391,7 +2414,9 @@
|
|||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -2468,6 +2493,38 @@
|
|||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[StochasticFairBlue] Section Options</title>
|
||||
<para>The <literal>[StochasticFairBlue]</literal> section manages the queueing discipline
|
||||
(qdisc) of stochastic fair blue (sfb).</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Handle=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the major number of unique identifier of the qdisc, known as the handle.
|
||||
Takes a number in hexadecimal ranges 1 to ffff. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PacketLimit=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the hard limit on the queue size in number of packets. When this limit is reached, incoming packets are
|
||||
dropped. An unsigned integer ranges 0 to 4294967294. Defaults to unset and kernel's default is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[StochasticFairnessQueueing] Section Options</title>
|
||||
<para>The <literal>[StochasticFairnessQueueing]</literal> section manages the queueing discipline
|
||||
|
@ -2478,7 +2535,9 @@
|
|||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -2499,6 +2558,82 @@
|
|||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[PFIFO] Section Options</title>
|
||||
<para>The <literal>[PFIFO]</literal> section manages the queueing discipline (qdisc) of
|
||||
Packet First In First Out (pfifo).</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Handle=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the major number of unique identifier of the qdisc, known as the handle.
|
||||
Takes a number in hexadecimal ranges 1 to ffff. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PacketLimit=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the hard limit on the FIFO size in number of packets. The size limit (a buffer size) to prevent it
|
||||
from overflowing in case it is unable to dequeue packets as quickly as it receives them. When this limit is reached,
|
||||
incoming packets are dropped. An unsigned integer ranges 0 to 4294967294. Defaults to unset and kernel's default is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[CAKE] Section Options</title>
|
||||
<para>The <literal>[CAKE]</literal> section manages the queueing discipline (qdisc) of
|
||||
Common Applications Kept Enhanced (CAKE).</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Handle=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the major number of unique identifier of the qdisc, known as the handle.
|
||||
Takes a number in hexadecimal ranges 1 to ffff. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Overhead=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies that bytes to be addeded to the size of each packet. Bytes may be negative.
|
||||
Takes an integer ranges -64 to 256. Defaults to unset and kernel's default is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Bandwidth=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the shaper bandwidth. When suffixed with K, M, or G, the specified size is
|
||||
parsed as Kilobits, Megabits, or Gigabits, respectively, to the base of 1000. Defaults to
|
||||
unset and kernel's default is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[ControlledDelay] Section Options</title>
|
||||
<para>The <literal>[ControlledDelay]</literal> section manages the queueing discipline (qdisc) of
|
||||
|
@ -2509,7 +2644,9 @@
|
|||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -2563,6 +2700,53 @@
|
|||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[GenericRandomEarlyDetection] Section Options</title>
|
||||
<para>The <literal>[GenericRandomEarlyDetection]</literal> section manages the queueing discipline
|
||||
(qdisc) of Generic Random Early Detection (GRED).</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Handle=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the major number of unique identifier of the qdisc, known as the handle.
|
||||
Takes a number in hexadecimal ranges 1 to ffff. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>VirtualQueues=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the number of virtual queues. Takes a integer in the range 1-16. Defaults to unset and kernel's default is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>DefaultVirtualQueue=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the number of default virtual queue. This must be less than <varname>VirtualQueue=</varname>.
|
||||
Defaults to unset and kernel's default is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>GenericRIO=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a boolean. It turns on the RIO-like buffering scheme. Defaults to
|
||||
unset and kernel's default is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[FairQueueingControlledDelay] Section Options</title>
|
||||
<para>The <literal>[FairQueueingControlledDelay]</literal> section manages the queueing discipline
|
||||
|
@ -2573,7 +2757,9 @@
|
|||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -2663,7 +2849,9 @@
|
|||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -2765,7 +2953,9 @@
|
|||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para>
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -2789,6 +2979,94 @@
|
|||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[HierarchyTokenBucket] Section Options</title>
|
||||
<para>The <literal>[HierarchyTokenBucket]</literal> section manages the queueing discipline (qdisc) of
|
||||
hierarchy token bucket (htb).</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
<literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
|
||||
major and minor number in hexadecimal ranges 1 to ffff separated with a colon
|
||||
(<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Handle=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the major number of unique identifier of the qdisc, known as the handle.
|
||||
Takes a number in hexadecimal ranges 1 to ffff. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>DefaultClass=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes the minor id in hexadecimal of the default class. Unclassified traffic gets sent
|
||||
to the class. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[HierarchyTokenBucketClass] Section Options</title>
|
||||
<para>The <literal>[HierarchyTokenBucketClass]</literal> section manages the traffic control class of
|
||||
hierarchy token bucket (htb).</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>Parent=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
|
||||
or a qdisc id. The qdisc id takes the major and minor number in hexadecimal ranges 1 to ffff
|
||||
separated with a colon (<literal>major:minor</literal>). Defaults to <literal>root</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ClassId=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the major and minur number of unique identifier of the class, known as the
|
||||
class ID. Each number is in hexadecimal ranges 1 to ffff. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Priority=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the priority of the class. In the round-robin process, classes with the lowest
|
||||
priority field are tried for packets first. This setting is mandatory.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Rate=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the maximum rate this class and all its children are guaranteed. When suffixed
|
||||
with K, M, or G, the specified size is parsed as Kilobits, Megabits, or Gigabits, respectively,
|
||||
to the base of 1000. This setting is mandatory.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>CeilRate=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the maximum rate at which a class can send, if its parent has bandwidth to spare.
|
||||
When suffixed with K, M, or G, the specified size is parsed as Kilobits, Megabits, or Gigabits,
|
||||
respectively, to the base of 1000. When unset, the value specified with <varname>Rate=</varname>
|
||||
is used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[BridgeVLAN] Section Options</title>
|
||||
<para>The <literal>[BridgeVLAN]</literal> section manages the VLAN ID configuration of a bridge port and accepts
|
||||
|
|
|
@ -649,9 +649,17 @@
|
|||
|
||||
<varlistentry>
|
||||
<term><varname>$SYSTEMD_UNIT_PATH</varname></term>
|
||||
<term><varname>$SYSTEMD_GENERATOR_PATH</varname></term>
|
||||
<term><varname>$SYSTEMD_ENVIRONMENT_GENERATOR_PATH</varname></term>
|
||||
|
||||
<listitem><para>Controls where systemd looks for unit
|
||||
files.</para></listitem>
|
||||
<listitem><para>Controls where systemd looks for unit files and
|
||||
generators.</para>
|
||||
<para>These variables may contain a list of paths, separated by colons
|
||||
(<literal>:</literal>). When set, if the list ends with an empty
|
||||
component (<literal>...:</literal>), this list is prepended to the
|
||||
usual set of of paths. Otherwise, the specified list replaces the usual
|
||||
set of paths.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -45,9 +45,13 @@ static inline int safe_atoux16(const char *s, uint16_t *ret) {
|
|||
|
||||
int safe_atoi16(const char *s, int16_t *ret);
|
||||
|
||||
static inline int safe_atou32(const char *s, uint32_t *ret_u) {
|
||||
static inline int safe_atou32_full(const char *s, unsigned base, uint32_t *ret_u) {
|
||||
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
|
||||
return safe_atou(s, (unsigned*) ret_u);
|
||||
return safe_atou_full(s, base, (unsigned*) ret_u);
|
||||
}
|
||||
|
||||
static inline int safe_atou32(const char *s, uint32_t *ret_u) {
|
||||
return safe_atou32_full(s, 0, (unsigned*) ret_u);
|
||||
}
|
||||
|
||||
static inline int safe_atoi32(const char *s, int32_t *ret_i) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <syslog.h>
|
||||
|
||||
#if HAVE_SELINUX
|
||||
#include <selinux/avc.h>
|
||||
#include <selinux/context.h>
|
||||
#include <selinux/label.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
@ -31,11 +32,14 @@
|
|||
DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
|
||||
#define _cleanup_context_free_ _cleanup_(context_freep)
|
||||
|
||||
static int mac_selinux_reload(int seqno);
|
||||
|
||||
static int cached_use = -1;
|
||||
static int cached_enforcing = -1;
|
||||
static struct selabel_handle *label_hnd = NULL;
|
||||
|
||||
#define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
|
||||
#define log_enforcing_errno(r, ...) log_full_errno(security_getenforce() == 1 ? LOG_ERR : LOG_WARNING, r, __VA_ARGS__)
|
||||
#define log_enforcing(...) log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
|
||||
#define log_enforcing_errno(r, ...) log_full_errno(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, r, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
bool mac_selinux_use(void) {
|
||||
|
@ -49,12 +53,37 @@ bool mac_selinux_use(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool mac_selinux_enforcing(void) {
|
||||
#if HAVE_SELINUX
|
||||
if (cached_enforcing < 0) {
|
||||
cached_enforcing = security_getenforce();
|
||||
if (cached_enforcing == -1) {
|
||||
log_error_errno(errno, "Failed to get SELinux enforced status: %m");
|
||||
}
|
||||
}
|
||||
|
||||
/* treat failure as enforced mode */
|
||||
return (cached_enforcing != 0);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mac_selinux_retest(void) {
|
||||
#if HAVE_SELINUX
|
||||
cached_use = -1;
|
||||
cached_enforcing = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAVE_SELINUX
|
||||
static int setenforce_callback(int enforcing) {
|
||||
cached_enforcing = enforcing;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mac_selinux_init(void) {
|
||||
int r = 0;
|
||||
|
||||
|
@ -62,6 +91,9 @@ int mac_selinux_init(void) {
|
|||
usec_t before_timestamp, after_timestamp;
|
||||
struct mallinfo before_mallinfo, after_mallinfo;
|
||||
|
||||
selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload);
|
||||
selinux_set_callback(SELINUX_CB_SETENFORCE, (union selinux_callback) setenforce_callback);
|
||||
|
||||
if (label_hnd)
|
||||
return 0;
|
||||
|
||||
|
@ -74,7 +106,7 @@ int mac_selinux_init(void) {
|
|||
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
||||
if (!label_hnd) {
|
||||
log_enforcing_errno(errno, "Failed to initialize SELinux context: %m");
|
||||
r = security_getenforce() == 1 ? -errno : 0;
|
||||
r = mac_selinux_enforcing() ? -errno : 0;
|
||||
} else {
|
||||
char timespan[FORMAT_TIMESPAN_MAX];
|
||||
int l;
|
||||
|
@ -104,13 +136,12 @@ void mac_selinux_finish(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void mac_selinux_reload(void) {
|
||||
|
||||
#if HAVE_SELINUX
|
||||
static int mac_selinux_reload(int seqno) {
|
||||
struct selabel_handle *backup_label_hnd;
|
||||
|
||||
if (!label_hnd)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
backup_label_hnd = TAKE_PTR(label_hnd);
|
||||
|
||||
|
@ -121,8 +152,10 @@ void mac_selinux_reload(void) {
|
|||
selabel_close(backup_label_hnd);
|
||||
else
|
||||
label_hnd = backup_label_hnd;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mac_selinux_fix(const char *path, LabelFixFlags flags) {
|
||||
|
||||
|
@ -151,6 +184,9 @@ int mac_selinux_fix(const char *path, LabelFixFlags flags) {
|
|||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
|
||||
(void) avc_netlink_check_nb();
|
||||
|
||||
if (selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode) < 0) {
|
||||
r = -errno;
|
||||
|
||||
|
@ -186,7 +222,7 @@ int mac_selinux_fix(const char *path, LabelFixFlags flags) {
|
|||
|
||||
fail:
|
||||
log_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", path);
|
||||
if (security_getenforce() == 1)
|
||||
if (mac_selinux_enforcing())
|
||||
return r;
|
||||
#endif
|
||||
|
||||
|
@ -204,7 +240,7 @@ int mac_selinux_apply(const char *path, const char *label) {
|
|||
|
||||
if (setfilecon(path, label) < 0) {
|
||||
log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
|
||||
if (security_getenforce() > 0)
|
||||
if (mac_selinux_enforcing())
|
||||
return -errno;
|
||||
}
|
||||
#endif
|
||||
|
@ -349,6 +385,9 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
|
|||
assert(abspath);
|
||||
assert(path_is_absolute(abspath));
|
||||
|
||||
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
|
||||
(void) avc_netlink_check_nb();
|
||||
|
||||
r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
|
||||
if (r < 0) {
|
||||
/* No context specified by the policy? Proceed without setting it. */
|
||||
|
@ -363,7 +402,7 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
|
|||
log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
|
||||
}
|
||||
|
||||
if (security_getenforce() > 0)
|
||||
if (mac_selinux_enforcing())
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
|
@ -444,7 +483,7 @@ int mac_selinux_create_socket_prepare(const char *label) {
|
|||
if (setsockcreatecon(label) < 0) {
|
||||
log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
|
||||
|
||||
if (security_getenforce() == 1)
|
||||
if (mac_selinux_enforcing())
|
||||
return -errno;
|
||||
}
|
||||
#endif
|
||||
|
@ -497,6 +536,9 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
|||
|
||||
path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
|
||||
|
||||
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
|
||||
(void) avc_netlink_check_nb();
|
||||
|
||||
if (path_is_absolute(path))
|
||||
r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
|
||||
else {
|
||||
|
@ -515,13 +557,13 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
|||
goto skipped;
|
||||
|
||||
log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
|
||||
if (security_getenforce() > 0)
|
||||
if (mac_selinux_enforcing())
|
||||
return -errno;
|
||||
|
||||
} else {
|
||||
if (setfscreatecon_raw(fcon) < 0) {
|
||||
log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
|
||||
if (security_getenforce() > 0)
|
||||
if (mac_selinux_enforcing())
|
||||
return -errno;
|
||||
} else
|
||||
context_changed = true;
|
||||
|
|
|
@ -16,11 +16,11 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
|
|||
#endif
|
||||
|
||||
bool mac_selinux_use(void);
|
||||
bool mac_selinux_enforcing(void);
|
||||
void mac_selinux_retest(void);
|
||||
|
||||
int mac_selinux_init(void);
|
||||
void mac_selinux_finish(void);
|
||||
void mac_selinux_reload(void);
|
||||
|
||||
int mac_selinux_fix(const char *path, LabelFixFlags flags);
|
||||
int mac_selinux_apply(const char *path, const char *label);
|
||||
|
|
|
@ -678,8 +678,8 @@ static int lookup_block_device(const char *p, dev_t *ret) {
|
|||
return log_warning_errno(r, "Failed to determine block device backing btrfs file system '%s': %m", p);
|
||||
}
|
||||
|
||||
/* If this is a LUKS device, try to get the originating block device */
|
||||
(void) block_get_originating(*ret, ret);
|
||||
/* If this is a LUKS/DM device, recursively try to get the originating block device */
|
||||
while (block_get_originating(*ret, ret) > 0);
|
||||
|
||||
/* If this is a partition, try to get the originating block device */
|
||||
(void) block_get_whole_disk(*ret, ret);
|
||||
|
|
|
@ -1747,8 +1747,6 @@ static int invoke_main_loop(
|
|||
saved_log_level = m->log_level_overridden ? log_get_max_level() : -1;
|
||||
saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID;
|
||||
|
||||
mac_selinux_reload();
|
||||
|
||||
(void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
|
||||
|
||||
set_manager_defaults(m);
|
||||
|
|
|
@ -3826,25 +3826,9 @@ static bool generator_path_any(const char* const* paths) {
|
|||
return found;
|
||||
}
|
||||
|
||||
static const char *const system_env_generator_binary_paths[] = {
|
||||
"/run/systemd/system-environment-generators",
|
||||
"/etc/systemd/system-environment-generators",
|
||||
"/usr/local/lib/systemd/system-environment-generators",
|
||||
SYSTEM_ENV_GENERATOR_PATH,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const user_env_generator_binary_paths[] = {
|
||||
"/run/systemd/user-environment-generators",
|
||||
"/etc/systemd/user-environment-generators",
|
||||
"/usr/local/lib/systemd/user-environment-generators",
|
||||
USER_ENV_GENERATOR_PATH,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int manager_run_environment_generators(Manager *m) {
|
||||
char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
|
||||
const char *const *paths;
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
void* args[] = {
|
||||
[STDOUT_GENERATE] = &tmp,
|
||||
[STDOUT_COLLECT] = &tmp,
|
||||
|
@ -3855,13 +3839,15 @@ static int manager_run_environment_generators(Manager *m) {
|
|||
if (MANAGER_IS_TEST_RUN(m) && !(m->test_run_flags & MANAGER_TEST_RUN_ENV_GENERATORS))
|
||||
return 0;
|
||||
|
||||
paths = MANAGER_IS_SYSTEM(m) ? system_env_generator_binary_paths : user_env_generator_binary_paths;
|
||||
paths = env_generator_binary_paths(MANAGER_IS_SYSTEM(m));
|
||||
if (!paths)
|
||||
return log_oom();
|
||||
|
||||
if (!generator_path_any(paths))
|
||||
if (!generator_path_any((const char* const*) paths))
|
||||
return 0;
|
||||
|
||||
RUN_WITH_UMASK(0022)
|
||||
r = execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment,
|
||||
r = execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, gather_environment,
|
||||
args, NULL, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -143,16 +143,16 @@ static int access_init(sd_bus_error *error) {
|
|||
return 1;
|
||||
|
||||
if (avc_open(NULL, 0) != 0) {
|
||||
int enforce, saved_errno = errno;
|
||||
int saved_errno = errno;
|
||||
const bool enforce = mac_selinux_enforcing();
|
||||
|
||||
enforce = security_getenforce();
|
||||
log_full_errno(enforce != 0 ? LOG_ERR : LOG_WARNING, saved_errno, "Failed to open the SELinux AVC: %m");
|
||||
log_full_errno(enforce ? LOG_ERR : LOG_WARNING, saved_errno, "Failed to open the SELinux AVC: %m");
|
||||
|
||||
/* If enforcement isn't on, then let's suppress this
|
||||
* error, and just don't do any AVC checks. The
|
||||
* warning we printed is hence all the admin will
|
||||
* see. */
|
||||
if (enforce == 0)
|
||||
if (!enforce)
|
||||
return 0;
|
||||
|
||||
/* Return an access denied error, if we couldn't load
|
||||
|
@ -185,7 +185,7 @@ int mac_selinux_generic_access_check(
|
|||
_cleanup_free_ char *cl = NULL;
|
||||
_cleanup_freecon_ char *fcon = NULL;
|
||||
char **cmdline = NULL;
|
||||
bool enforce = false; /* Will be set to the real value later if needed */
|
||||
const bool enforce = mac_selinux_enforcing();
|
||||
int r = 0;
|
||||
|
||||
assert(message);
|
||||
|
@ -223,7 +223,6 @@ int mac_selinux_generic_access_check(
|
|||
|
||||
if (getfilecon_raw(path, &fcon) < 0) {
|
||||
r = -errno;
|
||||
enforce = security_getenforce() > 0;
|
||||
|
||||
log_warning_errno(r, "SELinux getfilecon_raw on '%s' failed%s (perm=%s): %m",
|
||||
path,
|
||||
|
@ -240,7 +239,6 @@ int mac_selinux_generic_access_check(
|
|||
} else {
|
||||
if (getcon_raw(&fcon) < 0) {
|
||||
r = -errno;
|
||||
enforce = security_getenforce() > 0;
|
||||
|
||||
log_warning_errno(r, "SELinux getcon_raw failed%s (perm=%s): %m",
|
||||
enforce ? "" : ", ignoring",
|
||||
|
@ -266,7 +264,6 @@ int mac_selinux_generic_access_check(
|
|||
r = selinux_check_access(scon, fcon, tclass, permission, &audit_info);
|
||||
if (r < 0) {
|
||||
r = errno_or_else(EPERM);
|
||||
enforce = security_getenforce() > 0;
|
||||
|
||||
if (enforce)
|
||||
sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
|
||||
|
|
|
@ -829,6 +829,18 @@ _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_prefix_get_prefix(sd_radv_prefix *p, struct in6_addr *ret_in6_addr,
|
||||
unsigned char *ret_prefixlen) {
|
||||
assert_return(p, -EINVAL);
|
||||
assert_return(ret_in6_addr, -EINVAL);
|
||||
assert_return(ret_prefixlen, -EINVAL);
|
||||
|
||||
*ret_in6_addr = p->opt.in6_addr;
|
||||
*ret_prefixlen = p->opt.prefixlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
|
||||
assert_return(p, -EINVAL);
|
||||
|
||||
|
|
|
@ -343,6 +343,74 @@ int sd_netlink_message_append_u64(sd_netlink_message *m, unsigned short type, ui
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_append_s8(sd_netlink_message *m, unsigned short type, int8_t data) {
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
|
||||
r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S8);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = add_rtattr(m, type, &data, sizeof(int8_t));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_append_s16(sd_netlink_message *m, unsigned short type, int16_t data) {
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
|
||||
r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S16);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = add_rtattr(m, type, &data, sizeof(int16_t));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_append_s32(sd_netlink_message *m, unsigned short type, int32_t data) {
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
|
||||
r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S32);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = add_rtattr(m, type, &data, sizeof(int32_t));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_append_s64(sd_netlink_message *m, unsigned short type, int64_t data) {
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
|
||||
r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = add_rtattr(m, type, &data, sizeof(int64_t));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
|
||||
int r;
|
||||
|
||||
|
|
|
@ -745,6 +745,12 @@ static const NLTypeSystem rtnl_nexthop_type_system = {
|
|||
.types = rtnl_nexthop_types,
|
||||
};
|
||||
|
||||
static const NLType rtnl_tca_option_data_cake_types[] = {
|
||||
[TCA_CAKE_BASE_RATE64] = { .type = NETLINK_TYPE_U64 },
|
||||
[TCA_CAKE_OVERHEAD] = { .type = NETLINK_TYPE_S32 },
|
||||
[TCA_CAKE_MPU] = { .type = NETLINK_TYPE_U32 },
|
||||
};
|
||||
|
||||
static const NLType rtnl_tca_option_data_codel_types[] = {
|
||||
[TCA_CODEL_TARGET] = { .type = NETLINK_TYPE_U32 },
|
||||
[TCA_CODEL_LIMIT] = { .type = NETLINK_TYPE_U32 },
|
||||
|
@ -780,6 +786,23 @@ static const NLType rtnl_tca_option_data_fq_codel_types[] = {
|
|||
[TCA_FQ_CODEL_MEMORY_LIMIT] = { .type = NETLINK_TYPE_U32 },
|
||||
};
|
||||
|
||||
static const NLType rtnl_tca_option_data_gred_types[] = {
|
||||
[TCA_GRED_DPS] = { .size = sizeof(struct tc_gred_sopt) },
|
||||
};
|
||||
|
||||
static const NLType rtnl_tca_option_data_htb_types[] = {
|
||||
[TCA_HTB_PARMS] = { .size = sizeof(struct tc_htb_opt) },
|
||||
[TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) },
|
||||
[TCA_HTB_CTAB] = { .size = TC_RTAB_SIZE },
|
||||
[TCA_HTB_RTAB] = { .size = TC_RTAB_SIZE },
|
||||
[TCA_HTB_RATE64] = { .type = NETLINK_TYPE_U64 },
|
||||
[TCA_HTB_CEIL64] = { .type = NETLINK_TYPE_U64 },
|
||||
};
|
||||
|
||||
static const NLType rtnl_tca_option_data_sfb_types[] = {
|
||||
[TCA_SFB_PARMS] = { .size = sizeof(struct tc_sfb_qopt) },
|
||||
};
|
||||
|
||||
static const NLType rtnl_tca_option_data_tbf_types[] = {
|
||||
[TCA_TBF_PARMS] = { .size = sizeof(struct tc_tbf_qopt) },
|
||||
[TCA_TBF_RTAB] = { .size = TC_RTAB_SIZE },
|
||||
|
@ -791,21 +814,33 @@ static const NLType rtnl_tca_option_data_tbf_types[] = {
|
|||
};
|
||||
|
||||
static const char* const nl_union_tca_option_data_table[] = {
|
||||
[NL_UNION_TCA_OPTION_DATA_CAKE] = "cake",
|
||||
[NL_UNION_TCA_OPTION_DATA_CODEL] = "codel",
|
||||
[NL_UNION_TCA_OPTION_DATA_FQ] = "fq",
|
||||
[NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = "fq_codel",
|
||||
[NL_UNION_TCA_OPTION_DATA_GRED] = "gred",
|
||||
[NL_UNION_TCA_OPTION_DATA_HTB] = "htb",
|
||||
[NL_UNION_TCA_OPTION_DATA_SFB] = "sfb",
|
||||
[NL_UNION_TCA_OPTION_DATA_TBF] = "tbf",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(nl_union_tca_option_data, NLUnionTCAOptionData);
|
||||
|
||||
static const NLTypeSystem rtnl_tca_option_data_type_systems[] = {
|
||||
[NL_UNION_TCA_OPTION_DATA_CAKE] = { .count = ELEMENTSOF(rtnl_tca_option_data_cake_types),
|
||||
.types = rtnl_tca_option_data_cake_types },
|
||||
[NL_UNION_TCA_OPTION_DATA_CODEL] = { .count = ELEMENTSOF(rtnl_tca_option_data_codel_types),
|
||||
.types = rtnl_tca_option_data_codel_types },
|
||||
[NL_UNION_TCA_OPTION_DATA_FQ] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_types),
|
||||
.types = rtnl_tca_option_data_fq_types },
|
||||
[NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_codel_types),
|
||||
.types = rtnl_tca_option_data_fq_codel_types },
|
||||
[NL_UNION_TCA_OPTION_DATA_GRED] = { .count = ELEMENTSOF(rtnl_tca_option_data_gred_types),
|
||||
.types = rtnl_tca_option_data_gred_types },
|
||||
[NL_UNION_TCA_OPTION_DATA_HTB] = { .count = ELEMENTSOF(rtnl_tca_option_data_htb_types),
|
||||
.types = rtnl_tca_option_data_htb_types },
|
||||
[NL_UNION_TCA_OPTION_DATA_SFB] = { .count = ELEMENTSOF(rtnl_tca_option_data_sfb_types),
|
||||
.types = rtnl_tca_option_data_sfb_types },
|
||||
[NL_UNION_TCA_OPTION_DATA_TBF] = { .count = ELEMENTSOF(rtnl_tca_option_data_tbf_types),
|
||||
.types = rtnl_tca_option_data_tbf_types },
|
||||
};
|
||||
|
@ -818,16 +853,16 @@ static const NLTypeSystemUnion rtnl_tca_option_data_type_system_union = {
|
|||
.match = TCA_KIND,
|
||||
};
|
||||
|
||||
static const NLType rtnl_qdisc_types[] = {
|
||||
static const NLType rtnl_tca_types[] = {
|
||||
[TCA_KIND] = { .type = NETLINK_TYPE_STRING },
|
||||
[TCA_OPTIONS] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_tca_option_data_type_system_union },
|
||||
[TCA_INGRESS_BLOCK] = { .type = NETLINK_TYPE_U32 },
|
||||
[TCA_EGRESS_BLOCK] = { .type = NETLINK_TYPE_U32 },
|
||||
};
|
||||
|
||||
static const NLTypeSystem rtnl_qdisc_type_system = {
|
||||
.count = ELEMENTSOF(rtnl_qdisc_types),
|
||||
.types = rtnl_qdisc_types,
|
||||
static const NLTypeSystem rtnl_tca_type_system = {
|
||||
.count = ELEMENTSOF(rtnl_tca_types),
|
||||
.types = rtnl_tca_types,
|
||||
};
|
||||
|
||||
static const NLType error_types[] = {
|
||||
|
@ -868,9 +903,12 @@ static const NLType rtnl_types[] = {
|
|||
[RTM_NEWNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) },
|
||||
[RTM_DELNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) },
|
||||
[RTM_GETNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) },
|
||||
[RTM_NEWQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_qdisc_type_system, .size = sizeof(struct tcmsg) },
|
||||
[RTM_DELQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_qdisc_type_system, .size = sizeof(struct tcmsg) },
|
||||
[RTM_GETQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_qdisc_type_system, .size = sizeof(struct tcmsg) },
|
||||
[RTM_NEWQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
|
||||
[RTM_DELQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
|
||||
[RTM_GETQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
|
||||
[RTM_NEWTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
|
||||
[RTM_DELTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
|
||||
[RTM_GETTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
|
||||
};
|
||||
|
||||
const NLTypeSystem rtnl_type_system_root = {
|
||||
|
|
|
@ -9,6 +9,10 @@ enum {
|
|||
NETLINK_TYPE_U16, /* NLA_U16 */
|
||||
NETLINK_TYPE_U32, /* NLA_U32 */
|
||||
NETLINK_TYPE_U64, /* NLA_U64 */
|
||||
NETLINK_TYPE_S8, /* NLA_S8 */
|
||||
NETLINK_TYPE_S16, /* NLA_S16 */
|
||||
NETLINK_TYPE_S32, /* NLA_S32 */
|
||||
NETLINK_TYPE_S64, /* NLA_S64 */
|
||||
NETLINK_TYPE_STRING, /* NLA_STRING */
|
||||
NETLINK_TYPE_FLAG, /* NLA_FLAG */
|
||||
NETLINK_TYPE_IN_ADDR,
|
||||
|
@ -92,9 +96,13 @@ const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_;
|
|||
NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_;
|
||||
|
||||
typedef enum NLUnionTCAOptionData {
|
||||
NL_UNION_TCA_OPTION_DATA_CAKE,
|
||||
NL_UNION_TCA_OPTION_DATA_CODEL,
|
||||
NL_UNION_TCA_OPTION_DATA_FQ,
|
||||
NL_UNION_TCA_OPTION_DATA_FQ_CODEL,
|
||||
NL_UNION_TCA_OPTION_DATA_GRED,
|
||||
NL_UNION_TCA_OPTION_DATA_HTB,
|
||||
NL_UNION_TCA_OPTION_DATA_SFB,
|
||||
NL_UNION_TCA_OPTION_DATA_TBF,
|
||||
_NL_UNION_TCA_OPTION_DATA_MAX,
|
||||
_NL_UNION_TCA_OPTION_DATA_INVALID = -1,
|
||||
|
|
|
@ -47,6 +47,10 @@ static inline bool rtnl_message_type_is_qdisc(uint16_t type) {
|
|||
return IN_SET(type, RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC);
|
||||
}
|
||||
|
||||
static inline bool rtnl_message_type_is_tclass(uint16_t type) {
|
||||
return IN_SET(type, RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS);
|
||||
}
|
||||
|
||||
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
|
||||
int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, uint32_t mtu);
|
||||
int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names);
|
||||
|
|
|
@ -1077,3 +1077,46 @@ int sd_rtnl_message_set_qdisc_handle(sd_netlink_message *m, uint32_t handle) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_new_tclass(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int tcm_family, int tcm_ifindex) {
|
||||
struct tcmsg *tcm;
|
||||
int r;
|
||||
|
||||
assert_return(rtnl_message_type_is_tclass(nlmsg_type), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nlmsg_type == RTM_NEWTCLASS)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
|
||||
tcm = NLMSG_DATA((*ret)->hdr);
|
||||
tcm->tcm_family = tcm_family;
|
||||
tcm->tcm_ifindex = tcm_ifindex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_set_tclass_parent(sd_netlink_message *m, uint32_t parent) {
|
||||
struct tcmsg *tcm;
|
||||
|
||||
assert_return(rtnl_message_type_is_tclass(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
tcm = NLMSG_DATA(m->hdr);
|
||||
tcm->tcm_parent = parent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_set_tclass_handle(sd_netlink_message *m, uint32_t handle) {
|
||||
struct tcmsg *tcm;
|
||||
|
||||
assert_return(rtnl_message_type_is_tclass(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
tcm = NLMSG_DATA(m->hdr);
|
||||
tcm->tcm_handle = handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -107,22 +107,36 @@ sources = files('''
|
|||
networkd-util.h
|
||||
networkd-wifi.c
|
||||
networkd-wifi.h
|
||||
tc/cake.c
|
||||
tc/cake.h
|
||||
tc/codel.c
|
||||
tc/codel.h
|
||||
tc/fifo.c
|
||||
tc/fifo.h
|
||||
tc/fq.c
|
||||
tc/fq.h
|
||||
tc/fq-codel.c
|
||||
tc/fq-codel.h
|
||||
tc/gred.c
|
||||
tc/gred.h
|
||||
tc/htb.c
|
||||
tc/htb.h
|
||||
tc/netem.c
|
||||
tc/netem.h
|
||||
tc/qdisc.c
|
||||
tc/qdisc.h
|
||||
tc/sfb.c
|
||||
tc/sfb.h
|
||||
tc/sfq.c
|
||||
tc/sfq.h
|
||||
tc/tbf.c
|
||||
tc/tbf.h
|
||||
tc/tc-util.c
|
||||
tc/tc-util.h
|
||||
tc/tc.c
|
||||
tc/tc.h
|
||||
tc/tclass.c
|
||||
tc/tclass.h
|
||||
tc/teql.c
|
||||
tc/teql.h
|
||||
'''.split())
|
||||
|
|
|
@ -1943,6 +1943,48 @@ static int link_renew(int argc, char *argv[], void *userdata) {
|
|||
return k;
|
||||
}
|
||||
|
||||
static int link_force_renew_one(sd_bus *bus, int index, const char *name) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.network1",
|
||||
"/org/freedesktop/network1",
|
||||
"org.freedesktop.network1.Manager",
|
||||
"ForceRenewLink",
|
||||
&error,
|
||||
NULL,
|
||||
"i", index);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to force renew dynamic configuration of interface %s: %s",
|
||||
name, bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_force_renew(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
int index, i, k = 0, r;
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect system bus: %m");
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
index = resolve_interface_or_warn(&rtnl, argv[i]);
|
||||
if (index < 0)
|
||||
return index;
|
||||
|
||||
r = link_force_renew_one(bus, index, argv[i]);
|
||||
if (r < 0 && k >= 0)
|
||||
k = r;
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
static int verb_reload(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
|
@ -2029,6 +2071,7 @@ static int help(void) {
|
|||
" label Show current address label entries in the kernel\n"
|
||||
" delete DEVICES... Delete virtual netdevs\n"
|
||||
" renew DEVICES... Renew dynamic configurations\n"
|
||||
" forcerenew DEVICES... Trigger DHCP reconfiguration of all connected clients\n"
|
||||
" reconfigure DEVICES... Reconfigure interfaces\n"
|
||||
" reload Reload .network and .netdev files\n"
|
||||
"\nOptions:\n"
|
||||
|
@ -2130,6 +2173,7 @@ static int networkctl_main(int argc, char *argv[]) {
|
|||
{ "label", VERB_ANY, VERB_ANY, 0, list_address_labels },
|
||||
{ "delete", 2, VERB_ANY, 0, link_delete },
|
||||
{ "renew", 2, VERB_ANY, 0, link_renew },
|
||||
{ "forcerenew", 2, VERB_ANY, 0, link_force_renew },
|
||||
{ "reconfigure", 2, VERB_ANY, 0, verb_reconfigure },
|
||||
{ "reload", 1, 1, 0, verb_reload },
|
||||
{}
|
||||
|
|
|
@ -20,6 +20,24 @@
|
|||
#define ADDRESSES_PER_LINK_MAX 2048U
|
||||
#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
|
||||
|
||||
int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret) {
|
||||
assert(link);
|
||||
assert(ret);
|
||||
|
||||
/* see RFC4291 section 2.5.1 */
|
||||
ret->s6_addr[8] = link->mac.ether_addr_octet[0];
|
||||
ret->s6_addr[8] ^= 1 << 1;
|
||||
ret->s6_addr[9] = link->mac.ether_addr_octet[1];
|
||||
ret->s6_addr[10] = link->mac.ether_addr_octet[2];
|
||||
ret->s6_addr[11] = 0xff;
|
||||
ret->s6_addr[12] = 0xfe;
|
||||
ret->s6_addr[13] = link->mac.ether_addr_octet[3];
|
||||
ret->s6_addr[14] = link->mac.ether_addr_octet[4];
|
||||
ret->s6_addr[15] = link->mac.ether_addr_octet[5];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int address_new(Address **ret) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@ bool address_is_ready(const Address *a);
|
|||
int address_section_verify(Address *a);
|
||||
int configure_ipv4_duplicate_address_detection(Link *link, Address *address);
|
||||
|
||||
int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
|
||||
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
|
||||
|
||||
extern const struct hash_ops address_hash_ops;
|
||||
|
|
|
@ -20,5 +20,6 @@ struct ConfigPerfItem;
|
|||
%%
|
||||
Network.SpeedMeter, config_parse_bool, 0, offsetof(Manager, use_speed_meter)
|
||||
Network.SpeedMeterIntervalSec, config_parse_sec, 0, offsetof(Manager, speed_meter_interval_usec)
|
||||
Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes)
|
||||
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid)
|
||||
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid)
|
||||
|
|
|
@ -572,6 +572,35 @@ int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_e
|
|||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
int bus_link_method_force_renew(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Link *l = userdata;
|
||||
int r;
|
||||
|
||||
assert(l);
|
||||
|
||||
if (!l->network)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_UNMANAGED_INTERFACE,
|
||||
"Interface %s is not managed by systemd-networkd",
|
||||
l->ifname);
|
||||
|
||||
r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
|
||||
"org.freedesktop.network1.forcerenew",
|
||||
NULL, true, UID_INVALID,
|
||||
&l->manager->polkit_registry, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 1; /* Polkit will call us back */
|
||||
|
||||
if (l->dhcp_server) {
|
||||
r = sd_dhcp_server_forcerenew(l->dhcp_server);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
int bus_link_method_renew(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Link *l = userdata;
|
||||
int r;
|
||||
|
@ -651,6 +680,7 @@ const sd_bus_vtable link_vtable[] = {
|
|||
SD_BUS_METHOD("RevertNTP", NULL, NULL, bus_link_method_revert_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("RevertDNS", NULL, NULL, bus_link_method_revert_dns, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Renew", NULL, NULL, bus_link_method_renew, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ForceRenew", NULL, NULL, bus_link_method_force_renew, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Reconfigure", NULL, NULL, bus_link_method_reconfigure, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_VTABLE_END
|
||||
|
|
|
@ -31,4 +31,5 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
|
|||
int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_link_method_renew(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_link_method_force_renew(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "networkd-radv.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-wifi.h"
|
||||
#include "qdisc.h"
|
||||
#include "set.h"
|
||||
#include "socket-util.h"
|
||||
#include "stat-util.h"
|
||||
|
@ -42,6 +41,7 @@
|
|||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
#include "sysctl-util.h"
|
||||
#include "tc.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "udev-util.h"
|
||||
#include "util.h"
|
||||
|
@ -1116,7 +1116,7 @@ void link_check_ready(Link *link) {
|
|||
if (!link->routing_policy_rules_configured)
|
||||
return;
|
||||
|
||||
if (!link->qdiscs_configured)
|
||||
if (!link->tc_configured)
|
||||
return;
|
||||
|
||||
if (link_has_carrier(link) || !link->network->configure_without_carrier) {
|
||||
|
@ -1222,6 +1222,7 @@ static int link_set_bridge_fdb(Link *link) {
|
|||
static int link_request_set_addresses(Link *link) {
|
||||
AddressLabel *label;
|
||||
Address *ad;
|
||||
Prefix *p;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
@ -1257,6 +1258,35 @@ static int link_request_set_addresses(Link *link) {
|
|||
link->address_messages++;
|
||||
}
|
||||
|
||||
if (IN_SET(link->network->router_prefix_delegation,
|
||||
RADV_PREFIX_DELEGATION_STATIC,
|
||||
RADV_PREFIX_DELEGATION_BOTH))
|
||||
LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
|
||||
if (!p->assign)
|
||||
continue;
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not allocate address: %m");
|
||||
|
||||
r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
address->family = AF_INET6;
|
||||
r = address_configure(address, link, address_handler, true);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not set addresses: %m");
|
||||
if (r > 0)
|
||||
link->address_messages++;
|
||||
}
|
||||
|
||||
LIST_FOREACH(labels, label, link->network->address_labels) {
|
||||
r = address_label_configure(label, link, NULL, false);
|
||||
if (r < 0)
|
||||
|
@ -1523,6 +1553,17 @@ static int link_acquire_ipv6_conf(Link *link) {
|
|||
return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m");
|
||||
}
|
||||
|
||||
if (link_dhcp6_enabled(link) && link->network->dhcp6_without_ra) {
|
||||
assert(link->dhcp6_client);
|
||||
assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
|
||||
|
||||
r = dhcp6_request_address(link, true);
|
||||
if (r < 0 && r != -EBUSY)
|
||||
return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m");
|
||||
else
|
||||
log_link_debug(link, "Acquiring DHCPv6 lease");
|
||||
}
|
||||
|
||||
(void) dhcp6_request_prefix_delegation(link);
|
||||
|
||||
return 0;
|
||||
|
@ -2702,24 +2743,24 @@ static int link_configure_ipv4_dad(Link *link) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int link_configure_qdiscs(Link *link) {
|
||||
QDisc *qdisc;
|
||||
static int link_configure_traffic_control(Link *link) {
|
||||
TrafficControl *tc;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
link->qdiscs_configured = false;
|
||||
link->qdisc_messages = 0;
|
||||
link->tc_configured = false;
|
||||
link->tc_messages = 0;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(qdisc, link->network->qdiscs_by_section, i) {
|
||||
r = qdisc_configure(link, qdisc);
|
||||
ORDERED_HASHMAP_FOREACH(tc, link->network->tc_by_section, i) {
|
||||
r = traffic_control_configure(link, tc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->qdisc_messages == 0)
|
||||
link->qdiscs_configured = true;
|
||||
if (link->tc_messages == 0)
|
||||
link->tc_configured = true;
|
||||
else
|
||||
log_link_debug(link, "Configuring queuing discipline (qdisc)");
|
||||
log_link_debug(link, "Configuring traffic control");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2731,7 +2772,7 @@ static int link_configure(Link *link) {
|
|||
assert(link->network);
|
||||
assert(link->state == LINK_STATE_INITIALIZED);
|
||||
|
||||
r = link_configure_qdiscs(link);
|
||||
r = link_configure_traffic_control(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ typedef struct Link {
|
|||
unsigned nexthop_messages;
|
||||
unsigned routing_policy_rule_messages;
|
||||
unsigned routing_policy_rule_remove_messages;
|
||||
unsigned qdisc_messages;
|
||||
unsigned tc_messages;
|
||||
unsigned enslaving;
|
||||
|
||||
Set *addresses;
|
||||
|
@ -116,7 +116,7 @@ typedef struct Link {
|
|||
bool static_routes_ready:1;
|
||||
bool static_nexthops_configured:1;
|
||||
bool routing_policy_rules_configured:1;
|
||||
bool qdiscs_configured:1;
|
||||
bool tc_configured:1;
|
||||
bool setting_mtu:1;
|
||||
bool setting_genmode:1;
|
||||
bool ipv6_mtu_set:1;
|
||||
|
|
|
@ -191,6 +191,10 @@ static int bus_method_renew_link(sd_bus_message *message, void *userdata, sd_bus
|
|||
return call_link_method(userdata, message, bus_link_method_renew, error);
|
||||
}
|
||||
|
||||
static int bus_method_force_renew_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
return call_link_method(userdata, message, bus_link_method_force_renew, error);
|
||||
}
|
||||
|
||||
static int bus_method_reconfigure_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
return call_link_method(userdata, message, bus_link_method_reconfigure, error);
|
||||
}
|
||||
|
@ -249,6 +253,7 @@ const sd_bus_vtable manager_vtable[] = {
|
|||
SD_BUS_METHOD("RevertLinkNTP", "i", NULL, bus_method_revert_link_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("RevertLinkDNS", "i", NULL, bus_method_revert_link_dns, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("RenewLink", "i", NULL, bus_method_renew_link, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ForceRenewLink", "i", NULL, bus_method_force_renew_link, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ReconfigureLink", "i", NULL, bus_method_reconfigure_link, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Reload", NULL, NULL, bus_method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
|
|
|
@ -494,7 +494,8 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
|
|||
|
||||
log_link_debug(link,
|
||||
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
|
||||
type == RTM_DELROUTE ? "Forgetting" : route ? "Received remembered" : "Remembering",
|
||||
(!route && !link->manager->manage_foreign_routes) || type == RTM_DELROUTE ? "Forgetting" :
|
||||
route ? "Received remembered" : "Remembering",
|
||||
strna(buf_dst), strempty(buf_dst_prefixlen),
|
||||
strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
|
||||
format_route_scope(tmp->scope, buf_scope, sizeof buf_scope),
|
||||
|
@ -505,7 +506,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
|
|||
|
||||
switch (type) {
|
||||
case RTM_NEWROUTE:
|
||||
if (!route) {
|
||||
if (!route && link->manager->manage_foreign_routes) {
|
||||
/* A route appeared that we did not request */
|
||||
r = route_add_foreign(link, tmp, &route);
|
||||
if (r < 0) {
|
||||
|
@ -1747,6 +1748,7 @@ int manager_new(Manager **ret) {
|
|||
|
||||
*m = (Manager) {
|
||||
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
|
||||
.manage_foreign_routes = true,
|
||||
};
|
||||
|
||||
m->state_file = strdup("/run/systemd/netif/state");
|
||||
|
|
|
@ -30,6 +30,7 @@ struct Manager {
|
|||
bool enumerating:1;
|
||||
bool dirty:1;
|
||||
bool restarting:1;
|
||||
bool manage_foreign_routes;
|
||||
|
||||
Set *dirty_links;
|
||||
|
||||
|
|
|
@ -324,16 +324,10 @@ static int ndisc_router_generate_addresses(Link *link, unsigned prefixlen, uint3
|
|||
|
||||
*new_address = *address;
|
||||
|
||||
/* see RFC4291 section 2.5.1 */
|
||||
new_address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
|
||||
new_address->in_addr.in6.s6_addr[8] ^= 1 << 1;
|
||||
new_address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
|
||||
new_address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
|
||||
new_address->in_addr.in6.s6_addr[11] = 0xff;
|
||||
new_address->in_addr.in6.s6_addr[12] = 0xfe;
|
||||
new_address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
|
||||
new_address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
|
||||
new_address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
|
||||
r = generate_ipv6_eui_64_address(link, &new_address->in_addr.in6);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to generate EUI64 address: %m");
|
||||
|
||||
new_address->prefixlen = prefixlen;
|
||||
new_address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
|
||||
new_address->cinfo.ifa_prefered = lifetime_preferred;
|
||||
|
@ -800,7 +794,8 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
|||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
|
||||
|
||||
if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
|
||||
if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER) &&
|
||||
link->network->ipv6_accept_ra_start_dhcp6_client) {
|
||||
/* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
|
||||
r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
|
||||
if (r < 0 && r != -EBUSY)
|
||||
|
|
|
@ -14,6 +14,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
|
|||
#include "networkd-ndisc.h"
|
||||
#include "networkd-network.h"
|
||||
#include "qdisc.h"
|
||||
#include "tclass.h"
|
||||
#include "vlan-util.h"
|
||||
%}
|
||||
struct ConfigPerfItem;
|
||||
|
@ -188,10 +189,12 @@ DHCPv6.UseNTP, config_parse_bool,
|
|||
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
|
||||
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
|
||||
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
|
||||
DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra)
|
||||
IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
|
||||
IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
|
||||
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
|
||||
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
|
||||
IPv6AcceptRA.DHCPv6Client, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
|
||||
IPv6AcceptRA.RouteTable, config_parse_section_route_table, 0, 0
|
||||
IPv6AcceptRA.BlackList, config_parse_ndisc_black_listed_prefix, 0, 0
|
||||
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
|
||||
|
@ -245,6 +248,7 @@ IPv6Prefix.OnLink, config_parse_prefix_flags,
|
|||
IPv6Prefix.AddressAutoconfiguration, config_parse_prefix_flags, 0, 0
|
||||
IPv6Prefix.ValidLifetimeSec, config_parse_prefix_lifetime, 0, 0
|
||||
IPv6Prefix.PreferredLifetimeSec, config_parse_prefix_lifetime, 0, 0
|
||||
IPv6Prefix.Assign, config_parse_prefix_assign, 0, 0
|
||||
IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0
|
||||
IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0
|
||||
CAN.BitRate, config_parse_si_uint64, 0, offsetof(Network, can_bitrate)
|
||||
|
@ -253,6 +257,10 @@ CAN.RestartSec, config_parse_sec,
|
|||
CAN.TripleSampling, config_parse_tristate, 0, offsetof(Network, can_triple_sampling)
|
||||
QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0
|
||||
QDisc.Handle, config_parse_qdisc_handle, _QDISC_KIND_INVALID, 0
|
||||
CAKE.Parent, config_parse_qdisc_parent, QDISC_KIND_CAKE, 0
|
||||
CAKE.Handle, config_parse_qdisc_handle, QDISC_KIND_CAKE, 0
|
||||
CAKE.Bandwidth, config_parse_cake_bandwidth, QDISC_KIND_CAKE, 0
|
||||
CAKE.Overhead, config_parse_cake_overhead, QDISC_KIND_CAKE, 0
|
||||
ControlledDelay.Parent, config_parse_qdisc_parent, QDISC_KIND_CODEL, 0
|
||||
ControlledDelay.Handle, config_parse_qdisc_handle, QDISC_KIND_CODEL, 0
|
||||
ControlledDelay.PacketLimit, config_parse_controlled_delay_u32, QDISC_KIND_CODEL, 0
|
||||
|
@ -260,6 +268,9 @@ ControlledDelay.TargetSec, config_parse_controlled_delay_usec,
|
|||
ControlledDelay.IntervalSec, config_parse_controlled_delay_usec, QDISC_KIND_CODEL, 0
|
||||
ControlledDelay.CEThresholdSec, config_parse_controlled_delay_usec, QDISC_KIND_CODEL, 0
|
||||
ControlledDelay.ECN, config_parse_controlled_delay_bool, QDISC_KIND_CODEL, 0
|
||||
PFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO, 0
|
||||
PFIFO.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO, 0
|
||||
PFIFO.PacketLimit, config_parse_fifo_size, QDISC_KIND_PFIFO, 0
|
||||
FairQueueing.Parent, config_parse_qdisc_parent, QDISC_KIND_FQ, 0
|
||||
FairQueueing.Handle, config_parse_qdisc_handle, QDISC_KIND_FQ, 0
|
||||
FairQueueing.PacketLimit, config_parse_fair_queueing_u32, QDISC_KIND_FQ, 0
|
||||
|
@ -281,6 +292,19 @@ FairQueueingControlledDelay.TargetSec, config_parse_fair_queueing_controll
|
|||
FairQueueingControlledDelay.IntervalSec, config_parse_fair_queueing_controlled_delay_usec, QDISC_KIND_FQ_CODEL, 0
|
||||
FairQueueingControlledDelay.CEThresholdSec, config_parse_fair_queueing_controlled_delay_usec, QDISC_KIND_FQ_CODEL, 0
|
||||
FairQueueingControlledDelay.ECN, config_parse_fair_queueing_controlled_delay_bool, QDISC_KIND_FQ_CODEL, 0
|
||||
GenericRandomEarlyDetection.Parent, config_parse_qdisc_parent, QDISC_KIND_GRED, 0
|
||||
GenericRandomEarlyDetection.Handle, config_parse_qdisc_handle, QDISC_KIND_GRED, 0
|
||||
GenericRandomEarlyDetection.VirtualQueues, config_parse_generic_random_early_detection_u32, QDISC_KIND_GRED, 0
|
||||
GenericRandomEarlyDetection.DefaultVirtualQueue, config_parse_generic_random_early_detection_u32, QDISC_KIND_GRED, 0
|
||||
GenericRandomEarlyDetection.GenericRIO, config_parse_generic_random_early_detection_bool, QDISC_KIND_GRED, 0
|
||||
HierarchyTokenBucket.Parent, config_parse_qdisc_parent, QDISC_KIND_HTB, 0
|
||||
HierarchyTokenBucket.Handle, config_parse_qdisc_handle, QDISC_KIND_HTB, 0
|
||||
HierarchyTokenBucket.DefaultClass, config_parse_hierarchy_token_bucket_default_class, QDISC_KIND_HTB, 0
|
||||
HierarchyTokenBucketClass.Parent, config_parse_tclass_parent, TCLASS_KIND_HTB, 0
|
||||
HierarchyTokenBucketClass.ClassId, config_parse_tclass_classid, TCLASS_KIND_HTB, 0
|
||||
HierarchyTokenBucketClass.Priority, config_parse_hierarchy_token_bucket_u32, TCLASS_KIND_HTB, 0
|
||||
HierarchyTokenBucketClass.Rate, config_parse_hierarchy_token_bucket_rate, TCLASS_KIND_HTB, 0
|
||||
HierarchyTokenBucketClass.CeilRate, config_parse_hierarchy_token_bucket_rate, TCLASS_KIND_HTB, 0
|
||||
NetworkEmulator.Parent, config_parse_qdisc_parent, QDISC_KIND_NETEM, 0
|
||||
NetworkEmulator.Handle, config_parse_qdisc_handle, QDISC_KIND_NETEM, 0
|
||||
NetworkEmulator.DelaySec, config_parse_network_emulator_delay, QDISC_KIND_NETEM, 0
|
||||
|
@ -288,6 +312,9 @@ NetworkEmulator.DelayJitterSec, config_parse_network_emulator_delay
|
|||
NetworkEmulator.LossRate, config_parse_network_emulator_rate, QDISC_KIND_NETEM, 0
|
||||
NetworkEmulator.DuplicateRate, config_parse_network_emulator_rate, QDISC_KIND_NETEM, 0
|
||||
NetworkEmulator.PacketLimit, config_parse_network_emulator_packet_limit, QDISC_KIND_NETEM, 0
|
||||
StochasticFairBlue.Parent, config_parse_qdisc_parent, QDISC_KIND_SFB, 0
|
||||
StochasticFairBlue.Handle, config_parse_qdisc_handle, QDISC_KIND_SFB, 0
|
||||
StochasticFairBlue.PacketLimit, config_parse_stochastic_fair_blue_u32, QDISC_KIND_SFB, 0
|
||||
StochasticFairnessQueueing.Parent, config_parse_qdisc_parent, QDISC_KIND_SFQ, 0
|
||||
StochasticFairnessQueueing.Handle, config_parse_qdisc_handle, QDISC_KIND_SFQ, 0
|
||||
StochasticFairnessQueueing.PerturbPeriodSec, config_parse_stochastic_fairness_queueing_perturb_period, QDISC_KIND_SFQ, 0
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tc.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Let's assume that anything above this number is a user misconfiguration. */
|
||||
|
@ -154,7 +155,7 @@ int network_verify(Network *network) {
|
|||
Prefix *prefix, *prefix_next;
|
||||
Route *route, *route_next;
|
||||
FdbEntry *fdb, *fdb_next;
|
||||
QDisc *qdisc;
|
||||
TrafficControl *tc;
|
||||
Iterator i;
|
||||
|
||||
assert(network);
|
||||
|
@ -316,9 +317,9 @@ int network_verify(Network *network) {
|
|||
routing_policy_rule_free(rule);
|
||||
|
||||
bool has_root = false, has_clsact = false;
|
||||
ORDERED_HASHMAP_FOREACH(qdisc, network->qdiscs_by_section, i)
|
||||
if (qdisc_section_verify(qdisc, &has_root, &has_clsact) < 0)
|
||||
qdisc_free(qdisc);
|
||||
ORDERED_HASHMAP_FOREACH(tc, network->tc_by_section, i)
|
||||
if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0)
|
||||
traffic_control_free(tc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -451,6 +452,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
|||
.ipv6_accept_ra_use_onlink_prefix = true,
|
||||
.ipv6_accept_ra_route_table = RT_TABLE_MAIN,
|
||||
.ipv6_accept_ra_route_table_set = false,
|
||||
.ipv6_accept_ra_start_dhcp6_client = true,
|
||||
|
||||
.keep_configuration = _KEEP_CONFIGURATION_INVALID,
|
||||
|
||||
|
@ -483,10 +485,16 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
|||
"TrafficControlQueueingDiscipline\0"
|
||||
"CAN\0"
|
||||
"QDisc\0"
|
||||
"CAKE\0"
|
||||
"ControlledDelay\0"
|
||||
"PFIFO\0"
|
||||
"FairQueueing\0"
|
||||
"FairQueueingControlledDelay\0"
|
||||
"GenericRandomEarlyDetection\0"
|
||||
"HierarchyTokenBucket\0"
|
||||
"HierarchyTokenBucketClass\0"
|
||||
"NetworkEmulator\0"
|
||||
"StochasticFairBlue\0"
|
||||
"StochasticFairnessQueueing\0"
|
||||
"TokenBucketFilter\0"
|
||||
"TrivialLinkEqualizer\0",
|
||||
|
@ -690,7 +698,7 @@ static Network *network_free(Network *network) {
|
|||
hashmap_free(network->prefixes_by_section);
|
||||
hashmap_free(network->route_prefixes_by_section);
|
||||
hashmap_free(network->rules_by_section);
|
||||
ordered_hashmap_free_with_destructor(network->qdiscs_by_section, qdisc_free);
|
||||
ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
|
||||
|
||||
if (network->manager &&
|
||||
network->manager->duids_requesting_uuid)
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-util.h"
|
||||
#include "ordered-set.h"
|
||||
#include "qdisc.h"
|
||||
#include "resolve-util.h"
|
||||
|
||||
typedef enum IPv6PrivacyExtensions {
|
||||
|
@ -126,6 +125,7 @@ struct Network {
|
|||
/* DHCPv6 Client support*/
|
||||
bool dhcp6_use_dns;
|
||||
bool dhcp6_use_ntp;
|
||||
bool dhcp6_without_ra;
|
||||
uint8_t dhcp6_pd_length;
|
||||
struct in6_addr dhcp6_pd_address;
|
||||
|
||||
|
@ -213,6 +213,7 @@ struct Network {
|
|||
bool ipv6_accept_ra_use_dns;
|
||||
bool ipv6_accept_ra_use_autonomous_prefix;
|
||||
bool ipv6_accept_ra_use_onlink_prefix;
|
||||
bool ipv6_accept_ra_start_dhcp6_client;
|
||||
bool active_slave;
|
||||
bool primary_slave;
|
||||
DHCPUseDomains ipv6_accept_ra_use_domains;
|
||||
|
@ -274,7 +275,7 @@ struct Network {
|
|||
Hashmap *prefixes_by_section;
|
||||
Hashmap *route_prefixes_by_section;
|
||||
Hashmap *rules_by_section;
|
||||
OrderedHashmap *qdiscs_by_section;
|
||||
OrderedHashmap *tc_by_section;
|
||||
|
||||
/* All kinds of DNS configuration */
|
||||
struct in_addr_data *dns;
|
||||
|
|
|
@ -319,6 +319,46 @@ int config_parse_prefix_lifetime(const char *unit,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_prefix_assign(
|
||||
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 = userdata;
|
||||
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = prefix_new_static(network, filename, section_line, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = parse_boolean(rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse %s=, ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->assign = r;
|
||||
p = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_route_prefix(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
|
|
@ -28,6 +28,8 @@ struct Prefix {
|
|||
|
||||
sd_radv_prefix *radv_prefix;
|
||||
|
||||
bool assign;
|
||||
|
||||
LIST_FIELDS(Prefix, prefixes);
|
||||
};
|
||||
|
||||
|
@ -59,6 +61,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_router_preference);
|
|||
CONFIG_PARSER_PROTOTYPE(config_parse_prefix);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_flags);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_lifetime);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_assign);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_radv_dns);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_radv_search_domains);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_route_prefix);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[Network]
|
||||
#SpeedMeter=no
|
||||
#SpeedMeterIntervalSec=10sec
|
||||
#ManageForeignRoutes=yes
|
||||
|
||||
[DHCP]
|
||||
#DUIDType=vendor
|
||||
|
|
|
@ -139,6 +139,17 @@
|
|||
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.network1.forcerenew">
|
||||
<description gettext-domain="systemd">DHCP server sends force renew message</description>
|
||||
<message gettext-domain="systemd">Authentication is required to send force renew message.</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.network1.renew">
|
||||
<description gettext-domain="systemd">Renew dynamic addresses</description>
|
||||
<message gettext-domain="systemd">Authentication is required to renew dynamic addresses.</message>
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2020 VMware, Inc. */
|
||||
|
||||
#include <linux/pkt_sched.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "cake.h"
|
||||
#include "conf-parser.h"
|
||||
#include "netlink-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "qdisc.h"
|
||||
#include "string-util.h"
|
||||
|
||||
static int cake_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
CommonApplicationsKeptEnhanced *c;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
c = CAKE(qdisc);
|
||||
|
||||
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "cake");
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
|
||||
|
||||
if (c->bandwidth > 0) {
|
||||
r = sd_netlink_message_append_u64(req, TCA_CAKE_BASE_RATE64, c->bandwidth);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_CAKE_BASE_RATE64 attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_s32(req, TCA_CAKE_OVERHEAD, c->overhead);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_CAKE_OVERHEAD attribute: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_cake_bandwidth(
|
||||
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) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
CommonApplicationsKeptEnhanced *c;
|
||||
Network *network = data;
|
||||
uint64_t k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
c = CAKE(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
c->bandwidth = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_size(rvalue, 1000, &k);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->bandwidth = k/8;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_cake_overhead(
|
||||
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) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
CommonApplicationsKeptEnhanced *c;
|
||||
Network *network = data;
|
||||
int32_t v;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
c = CAKE(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
c->overhead = 0;
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atoi32(rvalue, &v);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse 'Overhead=', ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (v < -64 || v > 256) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid 'Overhead=', ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->overhead = v;
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable cake_vtable = {
|
||||
.object_size = sizeof(CommonApplicationsKeptEnhanced),
|
||||
.tca_kind = "cake",
|
||||
.fill_message = cake_fill_message,
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2020 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "qdisc.h"
|
||||
|
||||
typedef struct CommonApplicationsKeptEnhanced {
|
||||
QDisc meta;
|
||||
|
||||
int overhead;
|
||||
uint64_t bandwidth;
|
||||
|
||||
} CommonApplicationsKeptEnhanced;
|
||||
|
||||
DEFINE_QDISC_CAST(CAKE, CommonApplicationsKeptEnhanced);
|
||||
extern const QDiscVTable cake_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_cake_bandwidth);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_cake_overhead);
|
|
@ -0,0 +1,87 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2020 VMware, Inc. */
|
||||
|
||||
#include <linux/pkt_sched.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "fifo.h"
|
||||
#include "netlink-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
static int fifo_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
struct tc_fifo_qopt opt = {};
|
||||
FirstInFirstOut *fifo;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
fifo = PFIFO(qdisc);
|
||||
|
||||
opt.limit = fifo->limit;
|
||||
|
||||
r = sd_netlink_message_append_data(req, TCA_OPTIONS, &opt, sizeof(struct tc_fifo_qopt));
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_OPTIONS attribute: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_fifo_size(
|
||||
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) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
Network *network = data;
|
||||
FirstInFirstOut *fifo;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(QDISC_KIND_PFIFO, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
fifo = PFIFO(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
fifo->limit = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &fifo->limit);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable pfifo_vtable = {
|
||||
.object_size = sizeof(FirstInFirstOut),
|
||||
.tca_kind = "pfifo",
|
||||
.fill_message = fifo_fill_message,
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2020 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "qdisc.h"
|
||||
|
||||
typedef struct FirstInFirstOut {
|
||||
QDisc meta;
|
||||
|
||||
uint32_t limit;
|
||||
} FirstInFirstOut;
|
||||
|
||||
DEFINE_QDISC_CAST(PFIFO, FirstInFirstOut);
|
||||
extern const QDiscVTable pfifo_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_fifo_size);
|
|
@ -0,0 +1,193 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2020 VMware, Inc. */
|
||||
|
||||
#include <linux/pkt_sched.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "netlink-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "qdisc.h"
|
||||
#include "string-util.h"
|
||||
|
||||
static int generic_random_early_detection_init(QDisc *qdisc) {
|
||||
GenericRandomEarlyDetection *gred;
|
||||
|
||||
assert(qdisc);
|
||||
|
||||
gred = GRED(qdisc);
|
||||
|
||||
gred->grio = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generic_random_early_detection_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
GenericRandomEarlyDetection *gred;
|
||||
struct tc_gred_sopt opt = {};
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
gred = GRED(qdisc);
|
||||
|
||||
opt.DPs = gred->virtual_queues;
|
||||
opt.def_DP = gred->default_virtual_queue;
|
||||
|
||||
if (gred->grio >= 0)
|
||||
opt.grio = gred->grio;
|
||||
|
||||
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "gred");
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
|
||||
|
||||
r = sd_netlink_message_append_data(req, TCA_GRED_DPS, &opt, sizeof(struct tc_gred_sopt));
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_GRED_DPS attribute: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generic_random_early_detection_verify(QDisc *qdisc) {
|
||||
GenericRandomEarlyDetection *gred = GRED(qdisc);
|
||||
|
||||
if (gred->default_virtual_queue >= gred->virtual_queues)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: DefaultVirtualQueue= must be less than VirtualQueues=. "
|
||||
"Ignoring [GenericRandomEarlyDetection] section from line %u.",
|
||||
qdisc->section->filename, qdisc->section->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_generic_random_early_detection_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) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
GenericRandomEarlyDetection *gred;
|
||||
Network *network = data;
|
||||
uint32_t *p;
|
||||
uint32_t v;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(QDISC_KIND_GRED, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
gred = GRED(qdisc);
|
||||
|
||||
if (streq(lvalue, "VirtualQueues"))
|
||||
p = &gred->virtual_queues;
|
||||
else if (streq(lvalue, "DefaultVirtualQueue"))
|
||||
p = &gred->default_virtual_queue;
|
||||
else
|
||||
assert_not_reached("Invalid lvalue.");
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*p = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &v);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v > MAX_DPs) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
}
|
||||
|
||||
*p = v;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
int config_parse_generic_random_early_detection_bool(
|
||||
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) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
GenericRandomEarlyDetection *gred;
|
||||
Network *network = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(QDISC_KIND_GRED, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
gred = GRED(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
gred->grio = -1;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_boolean(rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gred->grio = r;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable gred_vtable = {
|
||||
.object_size = sizeof(GenericRandomEarlyDetection),
|
||||
.tca_kind = "gred",
|
||||
.init = generic_random_early_detection_init,
|
||||
.fill_message = generic_random_early_detection_fill_message,
|
||||
.verify = generic_random_early_detection_verify,
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2020 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "qdisc.h"
|
||||
|
||||
typedef struct GenericRandomEarlyDetection {
|
||||
QDisc meta;
|
||||
|
||||
uint32_t virtual_queues;
|
||||
uint32_t default_virtual_queue;
|
||||
int grio;
|
||||
} GenericRandomEarlyDetection;
|
||||
|
||||
DEFINE_QDISC_CAST(GRED, GenericRandomEarlyDetection);
|
||||
extern const QDiscVTable gred_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_generic_random_early_detection_u32);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_generic_random_early_detection_bool);
|
|
@ -0,0 +1,279 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <linux/pkt_sched.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "netlink-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "qdisc.h"
|
||||
#include "htb.h"
|
||||
#include "string-util.h"
|
||||
#include "tc-util.h"
|
||||
|
||||
static int hierarchy_token_bucket_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
HierarchyTokenBucket *htb;
|
||||
struct tc_htb_glob opt = {
|
||||
.rate2quantum = 10,
|
||||
.version = 3,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
htb = HTB(qdisc);
|
||||
|
||||
opt.defcls = htb->default_class;
|
||||
|
||||
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "htb");
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
|
||||
|
||||
r = sd_netlink_message_append_data(req, TCA_HTB_INIT, &opt, sizeof(opt));
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_HTB_INIT attribute: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_hierarchy_token_bucket_default_class(
|
||||
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) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
HierarchyTokenBucket *htb;
|
||||
Network *network = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(QDISC_KIND_HTB, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
htb = HTB(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
htb->default_class = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32_full(rvalue, 16, &htb->default_class);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable htb_vtable = {
|
||||
.object_size = sizeof(HierarchyTokenBucket),
|
||||
.tca_kind = "htb",
|
||||
.fill_message = hierarchy_token_bucket_fill_message,
|
||||
};
|
||||
|
||||
static int hierarchy_token_bucket_class_fill_message(Link *link, TClass *tclass, sd_netlink_message *req) {
|
||||
HierarchyTokenBucketClass *htb;
|
||||
struct tc_htb_opt opt = {};
|
||||
uint32_t rtab[256], ctab[256], mtu = 1600; /* Ethernet packet length */
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(tclass);
|
||||
assert(req);
|
||||
|
||||
htb = TCLASS_TO_HTB(tclass);
|
||||
|
||||
if (htb->ceil_rate == 0)
|
||||
htb->ceil_rate = htb->rate;
|
||||
|
||||
opt.prio = htb->priority;
|
||||
opt.rate.rate = (htb->rate >= (1ULL << 32)) ? ~0U : htb->rate;
|
||||
opt.ceil.rate = (htb->ceil_rate >= (1ULL << 32)) ? ~0U : htb->ceil_rate;
|
||||
r = tc_transmit_time(htb->rate, mtu, &opt.buffer);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to calculate buffer size: %m");
|
||||
|
||||
r = tc_transmit_time(htb->ceil_rate, mtu, &opt.cbuffer);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to calculate ceil buffer size: %m");
|
||||
|
||||
r = tc_fill_ratespec_and_table(&opt.rate, rtab, mtu);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to calculate rate table: %m");
|
||||
|
||||
r = tc_fill_ratespec_and_table(&opt.ceil, ctab, mtu);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to calculate ceil rate table: %m");
|
||||
|
||||
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "htb");
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
|
||||
|
||||
r = sd_netlink_message_append_data(req, TCA_HTB_PARMS, &opt, sizeof(opt));
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_HTB_PARMS attribute: %m");
|
||||
|
||||
if (htb->rate >= (1ULL << 32)) {
|
||||
r = sd_netlink_message_append_u64(req, TCA_HTB_RATE64, htb->rate);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_HTB_RATE64 attribute: %m");
|
||||
}
|
||||
|
||||
if (htb->ceil_rate >= (1ULL << 32)) {
|
||||
r = sd_netlink_message_append_u64(req, TCA_HTB_CEIL64, htb->ceil_rate);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_HTB_CEIL64 attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_data(req, TCA_HTB_RTAB, rtab, sizeof(rtab));
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_HTB_RTAB attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_data(req, TCA_HTB_CTAB, ctab, sizeof(ctab));
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_HTB_CTAB attribute: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_hierarchy_token_bucket_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) {
|
||||
|
||||
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
|
||||
HierarchyTokenBucketClass *htb;
|
||||
Network *network = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = tclass_new_static(TCLASS_KIND_HTB, network, filename, section_line, &tclass);
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to create traffic control class, ignoring assignment: %m");
|
||||
|
||||
htb = TCLASS_TO_HTB(tclass);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
htb->priority = 0;
|
||||
|
||||
tclass = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &htb->priority);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tclass = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_hierarchy_token_bucket_rate(
|
||||
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) {
|
||||
|
||||
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
|
||||
HierarchyTokenBucketClass *htb;
|
||||
Network *network = data;
|
||||
uint64_t *v;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = tclass_new_static(TCLASS_KIND_HTB, network, filename, section_line, &tclass);
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to create traffic control class, ignoring assignment: %m");
|
||||
|
||||
htb = TCLASS_TO_HTB(tclass);
|
||||
if (streq(lvalue, "Rate"))
|
||||
v = &htb->rate;
|
||||
else if (streq(lvalue, "CeilRate"))
|
||||
v = &htb->ceil_rate;
|
||||
else
|
||||
assert_not_reached("Invalid lvalue");
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*v = 0;
|
||||
|
||||
tclass = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_size(rvalue, 1000, v);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*v /= 8;
|
||||
tclass = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const TClassVTable htb_tclass_vtable = {
|
||||
.object_size = sizeof(HierarchyTokenBucketClass),
|
||||
.tca_kind = "htb",
|
||||
.fill_message = hierarchy_token_bucket_class_fill_message,
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "qdisc.h"
|
||||
#include "tclass.h"
|
||||
|
||||
typedef struct HierarchyTokenBucket {
|
||||
QDisc meta;
|
||||
|
||||
uint32_t default_class;
|
||||
} HierarchyTokenBucket;
|
||||
|
||||
DEFINE_QDISC_CAST(HTB, HierarchyTokenBucket);
|
||||
extern const QDiscVTable htb_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_default_class);
|
||||
|
||||
typedef struct HierarchyTokenBucketClass {
|
||||
TClass meta;
|
||||
|
||||
uint32_t priority;
|
||||
uint64_t rate;
|
||||
uint64_t ceil_rate;
|
||||
} HierarchyTokenBucketClass;
|
||||
|
||||
DEFINE_TCLASS_CAST(HTB, HierarchyTokenBucketClass);
|
||||
extern const TClassVTable htb_tclass_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_u32);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_rate);
|
|
@ -12,12 +12,19 @@
|
|||
#include "qdisc.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tc-util.h"
|
||||
|
||||
const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
|
||||
[QDISC_KIND_CAKE] = &cake_vtable,
|
||||
[QDISC_KIND_CODEL] = &codel_vtable,
|
||||
[QDISC_KIND_FQ] = &fq_vtable,
|
||||
[QDISC_KIND_FQ_CODEL] = &fq_codel_vtable,
|
||||
[QDISC_KIND_GRED] = &gred_vtable,
|
||||
[QDISC_KIND_HTB] = &htb_vtable,
|
||||
[QDISC_KIND_NETEM] = &netem_vtable,
|
||||
[QDISC_KIND_PFIFO] = &pfifo_vtable,
|
||||
[QDISC_KIND_SFB] = &sfb_vtable,
|
||||
[QDISC_KIND_SFQ] = &sfq_vtable,
|
||||
[QDISC_KIND_TBF] = &tbf_vtable,
|
||||
[QDISC_KIND_TEQL] = &teql_vtable,
|
||||
|
@ -33,6 +40,7 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) {
|
|||
return -ENOMEM;
|
||||
|
||||
*qdisc = (QDisc) {
|
||||
.meta.kind = TC_KIND_QDISC,
|
||||
.family = AF_UNSPEC,
|
||||
.parent = TC_H_ROOT,
|
||||
.kind = kind,
|
||||
|
@ -42,6 +50,7 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) {
|
|||
if (!qdisc)
|
||||
return -ENOMEM;
|
||||
|
||||
qdisc->meta.kind = TC_KIND_QDISC,
|
||||
qdisc->family = AF_UNSPEC;
|
||||
qdisc->parent = TC_H_ROOT;
|
||||
qdisc->kind = kind;
|
||||
|
@ -61,7 +70,8 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) {
|
|||
int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret) {
|
||||
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||
_cleanup_(qdisc_freep) QDisc *qdisc = NULL;
|
||||
QDisc *existing;
|
||||
TrafficControl *existing;
|
||||
QDisc *q = NULL;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
|
@ -73,15 +83,20 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
existing = ordered_hashmap_get(network->qdiscs_by_section, n);
|
||||
existing = ordered_hashmap_get(network->tc_by_section, n);
|
||||
if (existing) {
|
||||
if (existing->kind != _QDISC_KIND_INVALID &&
|
||||
kind != _QDISC_KIND_INVALID &&
|
||||
existing->kind != kind)
|
||||
if (existing->kind != TC_KIND_QDISC)
|
||||
return -EINVAL;
|
||||
|
||||
if (existing->kind == kind || kind == _QDISC_KIND_INVALID) {
|
||||
*ret = existing;
|
||||
q = TC_TO_QDISC(existing);
|
||||
|
||||
if (q->kind != _QDISC_KIND_INVALID &&
|
||||
kind != _QDISC_KIND_INVALID &&
|
||||
q->kind != kind)
|
||||
return -EINVAL;
|
||||
|
||||
if (q->kind == kind || kind == _QDISC_KIND_INVALID) {
|
||||
*ret = q;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -90,23 +105,23 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (existing) {
|
||||
qdisc->family = existing->family;
|
||||
qdisc->handle = existing->handle;
|
||||
qdisc->parent = existing->parent;
|
||||
qdisc->tca_kind = TAKE_PTR(existing->tca_kind);
|
||||
if (q) {
|
||||
qdisc->family = q->family;
|
||||
qdisc->handle = q->handle;
|
||||
qdisc->parent = q->parent;
|
||||
qdisc->tca_kind = TAKE_PTR(q->tca_kind);
|
||||
|
||||
qdisc_free(ordered_hashmap_remove(network->qdiscs_by_section, n));
|
||||
qdisc_free(q);
|
||||
}
|
||||
|
||||
qdisc->network = network;
|
||||
qdisc->section = TAKE_PTR(n);
|
||||
|
||||
r = ordered_hashmap_ensure_allocated(&network->qdiscs_by_section, &network_config_hash_ops);
|
||||
r = ordered_hashmap_ensure_allocated(&network->tc_by_section, &network_config_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_hashmap_put(network->qdiscs_by_section, qdisc->section, qdisc);
|
||||
r = ordered_hashmap_put(network->tc_by_section, qdisc->section, TC(qdisc));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -119,7 +134,7 @@ void qdisc_free(QDisc *qdisc) {
|
|||
return;
|
||||
|
||||
if (qdisc->network && qdisc->section)
|
||||
ordered_hashmap_remove(qdisc->network->qdiscs_by_section, qdisc->section);
|
||||
ordered_hashmap_remove(qdisc->network->tc_by_section, qdisc->section);
|
||||
|
||||
network_config_section_free(qdisc->section);
|
||||
|
||||
|
@ -131,8 +146,8 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->qdisc_messages > 0);
|
||||
link->qdisc_messages--;
|
||||
assert(link->tc_messages > 0);
|
||||
link->tc_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
@ -144,9 +159,9 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (link->qdisc_messages == 0) {
|
||||
log_link_debug(link, "QDisc configured");
|
||||
link->qdiscs_configured = true;
|
||||
if (link->tc_messages == 0) {
|
||||
log_link_debug(link, "Traffic control configured");
|
||||
link->tc_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
|
@ -203,7 +218,7 @@ int qdisc_configure(Link *link, QDisc *qdisc) {
|
|||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link);
|
||||
link->qdisc_messages++;
|
||||
link->tc_messages++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -279,19 +294,21 @@ int config_parse_qdisc_parent(
|
|||
qdisc->parent = TC_H_INGRESS;
|
||||
qdisc->handle = TC_H_MAKE(TC_H_INGRESS, 0);
|
||||
} else {
|
||||
r = parse_handle(rvalue, &qdisc->parent);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse 'Parent=', ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (streq(rvalue, "root"))
|
||||
qdisc->tca_kind = mfree(qdisc->tca_kind);
|
||||
else {
|
||||
if (STR_IN_SET(rvalue, "clsact", "ingress")) {
|
||||
r = free_and_strdup(&qdisc->tca_kind, rvalue);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
} else
|
||||
qdisc->tca_kind = mfree(qdisc->tca_kind);
|
||||
|
||||
qdisc = NULL;
|
||||
|
||||
|
|
|
@ -6,12 +6,18 @@
|
|||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
#include "tc.h"
|
||||
|
||||
typedef enum QDiscKind {
|
||||
QDISC_KIND_CAKE,
|
||||
QDISC_KIND_CODEL,
|
||||
QDISC_KIND_FQ,
|
||||
QDISC_KIND_FQ_CODEL,
|
||||
QDISC_KIND_GRED,
|
||||
QDISC_KIND_HTB,
|
||||
QDISC_KIND_NETEM,
|
||||
QDISC_KIND_PFIFO,
|
||||
QDISC_KIND_SFB,
|
||||
QDISC_KIND_SFQ,
|
||||
QDISC_KIND_TBF,
|
||||
QDISC_KIND_TEQL,
|
||||
|
@ -20,6 +26,8 @@ typedef enum QDiscKind {
|
|||
} QDiscKind;
|
||||
|
||||
typedef struct QDisc {
|
||||
TrafficControl meta;
|
||||
|
||||
NetworkConfigSection *section;
|
||||
Network *network;
|
||||
|
||||
|
@ -65,13 +73,20 @@ int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact);
|
|||
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(QDisc, qdisc_free);
|
||||
|
||||
DEFINE_TC_CAST(QDISC, QDisc);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_parent);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_handle);
|
||||
|
||||
#include "cake.h"
|
||||
#include "codel.h"
|
||||
#include "fifo.h"
|
||||
#include "fq-codel.h"
|
||||
#include "fq.h"
|
||||
#include "gred.h"
|
||||
#include "htb.h"
|
||||
#include "netem.h"
|
||||
#include "sfb.h"
|
||||
#include "sfq.h"
|
||||
#include "tbf.h"
|
||||
#include "teql.h"
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2020 VMware, Inc. */
|
||||
|
||||
#include <linux/pkt_sched.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "netlink-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "qdisc.h"
|
||||
#include "sfb.h"
|
||||
#include "string-util.h"
|
||||
|
||||
static int stochastic_fair_blue_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
StochasticFairBlue *sfb;
|
||||
struct tc_sfb_qopt opt = {
|
||||
.rehash_interval = 600*1000,
|
||||
.warmup_time = 60*1000,
|
||||
.penalty_rate = 10,
|
||||
.penalty_burst = 20,
|
||||
.increment = (SFB_MAX_PROB + 1000) / 2000,
|
||||
.decrement = (SFB_MAX_PROB + 10000) / 20000,
|
||||
.max = 25,
|
||||
.bin_size = 20,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
sfb = SFB(qdisc);
|
||||
|
||||
opt.limit = sfb->packet_limit;
|
||||
|
||||
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "sfb");
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
|
||||
|
||||
r = sd_netlink_message_append_data(req, TCA_SFB_PARMS, &opt, sizeof(struct tc_sfb_qopt));
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_SFB_PARMS attribute: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_stochastic_fair_blue_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) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
StochasticFairBlue *sfb;
|
||||
Network *network = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(QDISC_KIND_SFB, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
sfb = SFB(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
sfb->packet_limit = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &sfb->packet_limit);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable sfb_vtable = {
|
||||
.object_size = sizeof(StochasticFairBlue),
|
||||
.tca_kind = "sfb",
|
||||
.fill_message = stochastic_fair_blue_fill_message,
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2020 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "qdisc.h"
|
||||
|
||||
typedef struct StochasticFairBlue {
|
||||
QDisc meta;
|
||||
|
||||
uint32_t packet_limit;
|
||||
} StochasticFairBlue;
|
||||
|
||||
DEFINE_QDISC_CAST(SFB, StochasticFairBlue);
|
||||
extern const QDiscVTable sfb_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_stochastic_fair_blue_u32);
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright © 2019 VMware, Inc. */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "extract-word.h"
|
||||
#include "fileio.h"
|
||||
#include "parse-util.h"
|
||||
#include "tc-util.h"
|
||||
|
@ -92,3 +93,32 @@ int tc_fill_ratespec_and_table(struct tc_ratespec *rate, uint32_t *rtab, uint32_
|
|||
rate->linklayer = TC_LINKLAYER_ETHERNET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_handle(const char *t, uint32_t *ret) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
uint16_t major, minor;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(ret);
|
||||
|
||||
/* Extract the major number. */
|
||||
r = extract_first_word(&t, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EINVAL;
|
||||
if (!t)
|
||||
return -EINVAL;
|
||||
|
||||
r = safe_atou16_full(word, 16, &major);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = safe_atou16_full(t, 16, &minor);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = ((uint32_t) major << 16) | minor;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,3 +10,4 @@ int tc_time_to_tick(usec_t t, uint32_t *ret);
|
|||
int parse_tc_percent(const char *s, uint32_t *percent);
|
||||
int tc_transmit_time(uint64_t rate, uint32_t size, uint32_t *ret);
|
||||
int tc_fill_ratespec_and_table(struct tc_ratespec *rate, uint32_t *rtab, uint32_t mtu);
|
||||
int parse_handle(const char *t, uint32_t *ret);
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "macro.h"
|
||||
#include "qdisc.h"
|
||||
#include "tc.h"
|
||||
#include "tclass.h"
|
||||
|
||||
void traffic_control_free(TrafficControl *tc) {
|
||||
if (!tc)
|
||||
return;
|
||||
|
||||
switch (tc->kind) {
|
||||
case TC_KIND_QDISC:
|
||||
qdisc_free(TC_TO_QDISC(tc));
|
||||
break;
|
||||
case TC_KIND_TCLASS:
|
||||
tclass_free(TC_TO_TCLASS(tc));
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Invalid traffic control type");
|
||||
}
|
||||
}
|
||||
|
||||
int traffic_control_configure(Link *link, TrafficControl *tc) {
|
||||
assert(link);
|
||||
assert(tc);
|
||||
|
||||
switch(tc->kind) {
|
||||
case TC_KIND_QDISC:
|
||||
return qdisc_configure(link, TC_TO_QDISC(tc));
|
||||
case TC_KIND_TCLASS:
|
||||
return tclass_configure(link, TC_TO_TCLASS(tc));
|
||||
default:
|
||||
assert_not_reached("Invalid traffic control type");
|
||||
}
|
||||
}
|
||||
|
||||
int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact) {
|
||||
assert(tc);
|
||||
|
||||
switch(tc->kind) {
|
||||
case TC_KIND_QDISC:
|
||||
return qdisc_section_verify(TC_TO_QDISC(tc), qdisc_has_root, qdisc_has_clsact);
|
||||
case TC_KIND_TCLASS:
|
||||
return tclass_section_verify(TC_TO_TCLASS(tc));
|
||||
default:
|
||||
assert_not_reached("Invalid traffic control type");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include "networkd-link.h"
|
||||
|
||||
typedef enum TrafficControlKind {
|
||||
TC_KIND_QDISC,
|
||||
TC_KIND_TCLASS,
|
||||
TC_KIND_FILTER,
|
||||
_TC_KIND_MAX,
|
||||
_TC_KIND_INVALID = -1,
|
||||
} TrafficControlKind;
|
||||
|
||||
typedef struct TrafficControl {
|
||||
TrafficControlKind kind;
|
||||
} TrafficControl;
|
||||
|
||||
/* For casting a tc into the various tc kinds */
|
||||
#define DEFINE_TC_CAST(UPPERCASE, MixedCase) \
|
||||
static inline MixedCase* TC_TO_##UPPERCASE(TrafficControl *tc) { \
|
||||
if (_unlikely_(!tc || tc->kind != TC_KIND_##UPPERCASE)) \
|
||||
return NULL; \
|
||||
\
|
||||
return (MixedCase*) tc; \
|
||||
}
|
||||
|
||||
/* For casting the various tc kinds into a tc */
|
||||
#define TC(tc) (&(tc)->meta)
|
||||
|
||||
void traffic_control_free(TrafficControl *tc);
|
||||
int traffic_control_configure(Link *link, TrafficControl *tc);
|
||||
int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact);
|
|
@ -0,0 +1,277 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2019 VMware, Inc. */
|
||||
|
||||
#include <linux/pkt_sched.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "parse-util.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tc-util.h"
|
||||
#include "tclass.h"
|
||||
|
||||
const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX] = {
|
||||
[TCLASS_KIND_HTB] = &htb_tclass_vtable,
|
||||
};
|
||||
|
||||
static int tclass_new(TClassKind kind, TClass **ret) {
|
||||
TClass *tclass;
|
||||
int r;
|
||||
|
||||
tclass = malloc0(tclass_vtable[kind]->object_size);
|
||||
if (!tclass)
|
||||
return -ENOMEM;
|
||||
|
||||
tclass->meta.kind = TC_KIND_TCLASS,
|
||||
tclass->parent = TC_H_ROOT;
|
||||
tclass->kind = kind;
|
||||
|
||||
if (TCLASS_VTABLE(tclass)->init) {
|
||||
r = TCLASS_VTABLE(tclass)->init(tclass);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(tclass);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret) {
|
||||
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||
_cleanup_(tclass_freep) TClass *tclass = NULL;
|
||||
TrafficControl *existing;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
assert(filename);
|
||||
assert(section_line > 0);
|
||||
|
||||
r = network_config_section_new(filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
existing = ordered_hashmap_get(network->tc_by_section, n);
|
||||
if (existing) {
|
||||
TClass *t;
|
||||
|
||||
if (existing->kind != TC_KIND_TCLASS)
|
||||
return -EINVAL;
|
||||
|
||||
t = TC_TO_TCLASS(existing);
|
||||
|
||||
if (t->kind != kind)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = tclass_new(kind, &tclass);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
tclass->network = network;
|
||||
tclass->section = TAKE_PTR(n);
|
||||
|
||||
r = ordered_hashmap_ensure_allocated(&network->tc_by_section, &network_config_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_hashmap_put(network->tc_by_section, tclass->section, tclass);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(tclass);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tclass_free(TClass *tclass) {
|
||||
if (!tclass)
|
||||
return;
|
||||
|
||||
if (tclass->network && tclass->section)
|
||||
ordered_hashmap_remove(tclass->network->tc_by_section, tclass->section);
|
||||
|
||||
network_config_section_free(tclass->section);
|
||||
|
||||
free(tclass);
|
||||
}
|
||||
|
||||
static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->tc_messages > 0);
|
||||
link->tc_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_message_error_errno(link, m, r, "Could not set TClass");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (link->tc_messages == 0) {
|
||||
log_link_debug(link, "Traffic control configured");
|
||||
link->tc_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tclass_configure(Link *link, TClass *tclass) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->manager->rtnl);
|
||||
assert(link->ifindex > 0);
|
||||
|
||||
r = sd_rtnl_message_new_tclass(link->manager->rtnl, &req, RTM_NEWTCLASS, AF_UNSPEC, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not create RTM_NEWTCLASS message: %m");
|
||||
|
||||
r = sd_rtnl_message_set_tclass_parent(req, tclass->parent);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not create tcm_parent message: %m");
|
||||
|
||||
if (tclass->classid != TC_H_UNSPEC) {
|
||||
r = sd_rtnl_message_set_tclass_handle(req, tclass->classid);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not set tcm_handle message: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_string(req, TCA_KIND, TCLASS_VTABLE(tclass)->tca_kind);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m");
|
||||
|
||||
if (TCLASS_VTABLE(tclass)->fill_message) {
|
||||
r = TCLASS_VTABLE(tclass)->fill_message(link, tclass, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = netlink_call_async(link->manager->rtnl, NULL, req, tclass_handler, link_netlink_destroy_callback, link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link);
|
||||
link->tc_messages++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tclass_section_verify(TClass *tclass) {
|
||||
int r;
|
||||
|
||||
assert(tclass);
|
||||
|
||||
if (section_is_invalid(tclass->section))
|
||||
return -EINVAL;
|
||||
|
||||
if (TCLASS_VTABLE(tclass)->verify) {
|
||||
r = TCLASS_VTABLE(tclass)->verify(tclass);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_tclass_parent(
|
||||
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) {
|
||||
|
||||
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
|
||||
Network *network = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = tclass_new_static(ltype, network, filename, section_line, &tclass);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (streq(rvalue, "root"))
|
||||
tclass->parent = TC_H_ROOT;
|
||||
else {
|
||||
r = parse_handle(rvalue, &tclass->parent);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse 'Parent=', ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
tclass = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_tclass_classid(
|
||||
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) {
|
||||
|
||||
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
|
||||
Network *network = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = tclass_new_static(ltype, network, filename, section_line, &tclass);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
tclass->classid = TC_H_UNSPEC;
|
||||
tclass = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_handle(rvalue, &tclass->classid);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse 'ClassId=', ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tclass = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+
|
||||
* Copyright © 2019 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
#include "tc.h"
|
||||
|
||||
typedef enum TClassKind {
|
||||
TCLASS_KIND_HTB,
|
||||
_TCLASS_KIND_MAX,
|
||||
_TCLASS_KIND_INVALID = -1,
|
||||
} TClassKind;
|
||||
|
||||
typedef struct TClass {
|
||||
TrafficControl meta;
|
||||
|
||||
NetworkConfigSection *section;
|
||||
Network *network;
|
||||
|
||||
uint32_t classid;
|
||||
uint32_t parent;
|
||||
|
||||
TClassKind kind;
|
||||
} TClass;
|
||||
|
||||
typedef struct TClassVTable {
|
||||
size_t object_size;
|
||||
const char *tca_kind;
|
||||
/* called in tclass_new() */
|
||||
int (*init)(TClass *tclass);
|
||||
int (*fill_message)(Link *link, TClass *tclass, sd_netlink_message *m);
|
||||
int (*verify)(TClass *tclass);
|
||||
} TClassVTable;
|
||||
|
||||
extern const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX];
|
||||
|
||||
#define TCLASS_VTABLE(t) ((t)->kind != _TCLASS_KIND_INVALID ? tclass_vtable[(t)->kind] : NULL)
|
||||
|
||||
/* For casting a tclass into the various tclass kinds */
|
||||
#define DEFINE_TCLASS_CAST(UPPERCASE, MixedCase) \
|
||||
static inline MixedCase* TCLASS_TO_##UPPERCASE(TClass *t) { \
|
||||
if (_unlikely_(!t || t->kind != TCLASS_KIND_##UPPERCASE)) \
|
||||
return NULL; \
|
||||
\
|
||||
return (MixedCase*) t; \
|
||||
}
|
||||
|
||||
/* For casting the various tclass kinds into a tclass */
|
||||
#define TCLASS(t) (&(t)->meta)
|
||||
|
||||
void tclass_free(TClass *tclass);
|
||||
int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret);
|
||||
|
||||
int tclass_configure(Link *link, TClass *tclass);
|
||||
int tclass_section_verify(TClass *tclass);
|
||||
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(TClass, tclass_free);
|
||||
|
||||
DEFINE_TC_CAST(TCLASS, TClass);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tclass_parent);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tclass_classid);
|
||||
|
||||
#include "htb.h"
|
|
@ -56,6 +56,9 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
|
|||
}
|
||||
|
||||
if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) {
|
||||
if (server->server_name)
|
||||
gnutls_session_set_verify_cert(gs, server->server_name, 0);
|
||||
else {
|
||||
stream->dnstls_data.validation.type = GNUTLS_DT_IP_ADDRESS;
|
||||
if (server->family == AF_INET) {
|
||||
stream->dnstls_data.validation.data = (unsigned char*) &server->address.in.s_addr;
|
||||
|
@ -66,6 +69,7 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
|
|||
}
|
||||
gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (server->server_name) {
|
||||
r = gnutls_server_name_set(gs, GNUTLS_NAME_DNS, server->server_name, strlen(server->server_name));
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#include "io-util.h"
|
||||
#include "resolved-dns-stream.h"
|
||||
|
@ -80,14 +81,20 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
|
|||
|
||||
if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) {
|
||||
X509_VERIFY_PARAM *v;
|
||||
const unsigned char *ip;
|
||||
|
||||
SSL_set_verify(s, SSL_VERIFY_PEER, NULL);
|
||||
v = SSL_get0_param(s);
|
||||
if (server->server_name) {
|
||||
X509_VERIFY_PARAM_set_hostflags(v, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
if (X509_VERIFY_PARAM_set1_host(v, server->server_name, 0) == 0)
|
||||
return -ECONNREFUSED;
|
||||
} else {
|
||||
const unsigned char *ip;
|
||||
ip = server->family == AF_INET ? (const unsigned char*) &server->address.in.s_addr : server->address.in6.s6_addr;
|
||||
if (X509_VERIFY_PARAM_set1_ip(v, ip, FAMILY_ADDRESS_SIZE(server->family)) == 0)
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (server->server_name) {
|
||||
r = SSL_set_tlsext_host_name(s, server->server_name);
|
||||
|
|
|
@ -851,6 +851,55 @@ int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg) {
|
||||
struct ethtool_pauseparam ecmd = {
|
||||
.cmd = ETHTOOL_GPAUSEPARAM
|
||||
};
|
||||
struct ifreq ifr = {
|
||||
.ifr_data = (void*) &ecmd
|
||||
};
|
||||
|
||||
bool need_update = false;
|
||||
int r;
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect_or_warn(fd, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
|
||||
r = ioctl(*fd, SIOCETHTOOL, &ifr);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (rx >= 0 && ecmd.rx_pause != (uint32_t) rx) {
|
||||
ecmd.rx_pause = rx;
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
if (tx >= 0 && ecmd.tx_pause != (uint32_t) tx) {
|
||||
ecmd.tx_pause = tx;
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
if (autoneg >= 0 && ecmd.autoneg != (uint32_t) autoneg) {
|
||||
ecmd.autoneg = autoneg;
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
if (need_update) {
|
||||
ecmd.cmd = ETHTOOL_SPAUSEPARAM;
|
||||
|
||||
r = ioctl(*fd, SIOCETHTOOL, &ifr);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_channel(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
|
|
@ -103,6 +103,7 @@ int ethtool_set_glinksettings(int *ethtool_fd, const char *ifname,
|
|||
int autonegotiation, uint32_t advertise[static N_ADVERTISE],
|
||||
uint64_t speed, Duplex duplex, NetDevPort port);
|
||||
int ethtool_set_channels(int *ethtool_fd, const char *ifname, netdev_channels *channels);
|
||||
int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg);
|
||||
|
||||
const char *duplex_to_string(Duplex d) _const_;
|
||||
Duplex duplex_from_string(const char *d) _pure_;
|
||||
|
|
|
@ -479,6 +479,36 @@ static int patch_root_prefix_strv(char **l, const char *root_dir) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int get_paths_from_environ(const char *var, char ***paths, bool *append) {
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(var);
|
||||
assert(paths);
|
||||
assert(append);
|
||||
|
||||
*append = false;
|
||||
|
||||
e = getenv(var);
|
||||
if (e) {
|
||||
const char *k;
|
||||
|
||||
k = endswith(e, ":");
|
||||
if (k) {
|
||||
e = strndupa(e, k - e);
|
||||
*append = true;
|
||||
}
|
||||
|
||||
/* FIXME: empty components in other places should be rejected. */
|
||||
|
||||
r = path_split_and_make_absolute(e, paths);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_paths_init(
|
||||
LookupPaths *p,
|
||||
UnitFileScope scope,
|
||||
|
@ -496,7 +526,6 @@ int lookup_paths_init(
|
|||
*persistent_attached = NULL, *runtime_attached = NULL;
|
||||
bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
@ -562,22 +591,9 @@ int lookup_paths_init(
|
|||
return r;
|
||||
|
||||
/* First priority is whatever has been passed to us via env vars */
|
||||
e = getenv("SYSTEMD_UNIT_PATH");
|
||||
if (e) {
|
||||
const char *k;
|
||||
|
||||
k = endswith(e, ":");
|
||||
if (k) {
|
||||
e = strndupa(e, k - e);
|
||||
append = true;
|
||||
}
|
||||
|
||||
/* FIXME: empty components in other places should be rejected. */
|
||||
|
||||
r = path_split_and_make_absolute(e, &paths);
|
||||
r = get_paths_from_environ("SYSTEMD_UNIT_PATH", &paths, &append);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!paths || append) {
|
||||
/* Let's figure something out. */
|
||||
|
@ -817,23 +833,90 @@ void lookup_paths_flush_generator(LookupPaths *p) {
|
|||
}
|
||||
|
||||
char **generator_binary_paths(UnitFileScope scope) {
|
||||
bool append = false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
int r;
|
||||
|
||||
/* First priority is whatever has been passed to us via env vars */
|
||||
r = get_paths_from_environ("SYSTEMD_GENERATOR_PATH", &paths, &append);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
if (!paths || append) {
|
||||
_cleanup_strv_free_ char **add = NULL;
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case UNIT_FILE_SYSTEM:
|
||||
return strv_new("/run/systemd/system-generators",
|
||||
add = strv_new("/run/systemd/system-generators",
|
||||
"/etc/systemd/system-generators",
|
||||
"/usr/local/lib/systemd/system-generators",
|
||||
SYSTEM_GENERATOR_PATH);
|
||||
break;
|
||||
|
||||
case UNIT_FILE_GLOBAL:
|
||||
case UNIT_FILE_USER:
|
||||
return strv_new("/run/systemd/user-generators",
|
||||
add = strv_new("/run/systemd/user-generators",
|
||||
"/etc/systemd/user-generators",
|
||||
"/usr/local/lib/systemd/user-generators",
|
||||
USER_GENERATOR_PATH);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Hmm, unexpected scope.");
|
||||
}
|
||||
|
||||
if (!add)
|
||||
return NULL;
|
||||
|
||||
if (paths) {
|
||||
r = strv_extend_strv(&paths, add, true);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
} else
|
||||
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
|
||||
* and don't have to copy anything */
|
||||
paths = TAKE_PTR(add);
|
||||
}
|
||||
|
||||
return TAKE_PTR(paths);
|
||||
}
|
||||
|
||||
char **env_generator_binary_paths(bool is_system) {
|
||||
bool append = false; /* Add items from SYSTEMD_ENVIRONMENT_GENERATOR_PATH before normal directories */
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
_cleanup_strv_free_ char **add = NULL;
|
||||
int r;
|
||||
|
||||
/* First priority is whatever has been passed to us via env vars */
|
||||
r = get_paths_from_environ("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", &paths, &append);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
if (!paths || append) {
|
||||
if (is_system)
|
||||
add = strv_new("/run/systemd/system-environment-generators",
|
||||
"/etc/systemd/system-environment-generators",
|
||||
"/usr/local/lib/systemd/system-environment-generators",
|
||||
SYSTEM_ENV_GENERATOR_PATH);
|
||||
else
|
||||
add = strv_new("/run/systemd/user-environment-generators",
|
||||
"/etc/systemd/user-environment-generators",
|
||||
"/usr/local/lib/systemd/user-environment-generators",
|
||||
USER_ENV_GENERATOR_PATH);
|
||||
|
||||
if (!add)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (paths) {
|
||||
r = strv_extend_strv(&paths, add, true);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
} else
|
||||
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
|
||||
* and don't have to copy anything */
|
||||
paths = TAKE_PTR(add);
|
||||
|
||||
return TAKE_PTR(paths);
|
||||
}
|
||||
|
|
|
@ -72,3 +72,4 @@ void lookup_paths_flush_generator(LookupPaths *p);
|
|||
void lookup_paths_free(LookupPaths *p);
|
||||
|
||||
char **generator_binary_paths(UnitFileScope scope);
|
||||
char **env_generator_binary_paths(bool is_system);
|
||||
|
|
|
@ -86,6 +86,10 @@ int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uin
|
|||
int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data);
|
||||
int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data);
|
||||
int sd_netlink_message_append_u64(sd_netlink_message *m, unsigned short type, uint64_t data);
|
||||
int sd_netlink_message_append_s8(sd_netlink_message *m, unsigned short type, int8_t data);
|
||||
int sd_netlink_message_append_s16(sd_netlink_message *m, unsigned short type, int16_t data);
|
||||
int sd_netlink_message_append_s32(sd_netlink_message *m, unsigned short type, int32_t data);
|
||||
int sd_netlink_message_append_s64(sd_netlink_message *m, unsigned short type, int64_t data);
|
||||
int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len);
|
||||
int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data);
|
||||
int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data);
|
||||
|
@ -208,6 +212,10 @@ int sd_rtnl_message_new_qdisc(sd_netlink *rtnl, sd_netlink_message **ret, uint16
|
|||
int sd_rtnl_message_set_qdisc_parent(sd_netlink_message *m, uint32_t parent);
|
||||
int sd_rtnl_message_set_qdisc_handle(sd_netlink_message *m, uint32_t handle);
|
||||
|
||||
int sd_rtnl_message_new_tclass(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int tcm_family, int tcm_ifindex);
|
||||
int sd_rtnl_message_set_tclass_parent(sd_netlink_message *m, uint32_t parent);
|
||||
int sd_rtnl_message_set_tclass_handle(sd_netlink_message *m, uint32_t handle);
|
||||
|
||||
/* genl */
|
||||
int sd_genl_socket_open(sd_netlink **nl);
|
||||
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m);
|
||||
|
|
|
@ -74,6 +74,8 @@ sd_radv_prefix *sd_radv_prefix_unref(sd_radv_prefix *ra);
|
|||
|
||||
int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
|
||||
unsigned char prefixlen);
|
||||
int sd_radv_prefix_get_prefix(sd_radv_prefix *p, struct in6_addr *ret_in6_addr,
|
||||
unsigned char *ret_prefixlen);
|
||||
int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink);
|
||||
int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
|
||||
int address_autoconfiguration);
|
||||
|
|
|
@ -67,15 +67,54 @@ static void test_user_and_global_paths(void) {
|
|||
log_info("+ %s", *p);
|
||||
}
|
||||
|
||||
static void print_generator_binary_paths(UnitFileScope scope) {
|
||||
_cleanup_strv_free_ char **paths;
|
||||
static void test_generator_binary_paths(UnitFileScope scope) {
|
||||
char template[] = "/tmp/test-path-lookup.XXXXXXX";
|
||||
|
||||
_cleanup_strv_free_ char **gp_without_env = NULL;
|
||||
_cleanup_strv_free_ char **env_gp_without_env = NULL;
|
||||
_cleanup_strv_free_ char **gp_with_env = NULL;
|
||||
_cleanup_strv_free_ char **env_gp_with_env = NULL;
|
||||
char *systemd_generator_path = NULL;
|
||||
char *systemd_env_generator_path = NULL;
|
||||
char **dir;
|
||||
|
||||
log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
assert_se(mkdtemp(template));
|
||||
|
||||
paths = generator_binary_paths(scope);
|
||||
STRV_FOREACH(dir, paths)
|
||||
assert_se(unsetenv("SYSTEMD_GENERATOR_PATH") == 0);
|
||||
assert_se(unsetenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH") == 0);
|
||||
|
||||
gp_without_env = generator_binary_paths(scope);
|
||||
env_gp_without_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false);
|
||||
|
||||
log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
STRV_FOREACH(dir, gp_without_env)
|
||||
log_info(" %s", *dir);
|
||||
|
||||
log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
STRV_FOREACH(dir, env_gp_without_env)
|
||||
log_info(" %s", *dir);
|
||||
|
||||
assert_se(!strv_isempty(gp_without_env));
|
||||
assert_se(!strv_isempty(env_gp_without_env));
|
||||
|
||||
systemd_generator_path = strjoina(template, "/systemd-generator-path");
|
||||
systemd_env_generator_path = strjoina(template, "/systemd-environment-generator-path");
|
||||
assert_se(setenv("SYSTEMD_GENERATOR_PATH", systemd_generator_path, 1) == 0);
|
||||
assert_se(setenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", systemd_env_generator_path, 1) == 0);
|
||||
|
||||
gp_with_env = generator_binary_paths(scope);
|
||||
env_gp_with_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false);
|
||||
|
||||
log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
STRV_FOREACH(dir, gp_with_env)
|
||||
log_info(" %s", *dir);
|
||||
|
||||
log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
STRV_FOREACH(dir, env_gp_with_env)
|
||||
log_info(" %s", *dir);
|
||||
|
||||
assert_se(strv_equal(gp_with_env, STRV_MAKE(systemd_generator_path)));
|
||||
assert_se(strv_equal(env_gp_with_env, STRV_MAKE(systemd_env_generator_path)));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -87,8 +126,8 @@ int main(int argc, char **argv) {
|
|||
|
||||
test_user_and_global_paths();
|
||||
|
||||
print_generator_binary_paths(UNIT_FILE_SYSTEM);
|
||||
print_generator_binary_paths(UNIT_FILE_USER);
|
||||
test_generator_binary_paths(UNIT_FILE_SYSTEM);
|
||||
test_generator_binary_paths(UNIT_FILE_USER);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -60,3 +60,6 @@ Link.CombinedChannels, config_parse_channel, 0,
|
|||
Link.Advertise, config_parse_advertise, 0, offsetof(link_config, advertise)
|
||||
Link.RxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring)
|
||||
Link.TxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring)
|
||||
Link.RxFlowControl, config_parse_tristate, 0, offsetof(link_config, rx_flow_control)
|
||||
Link.TxFlowControl, config_parse_tristate, 0, offsetof(link_config, tx_flow_control)
|
||||
Link.AutoNegotiationFlowControl, config_parse_tristate, 0, offsetof(link_config, autoneg_flow_control)
|
||||
|
|
|
@ -148,6 +148,9 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
|
|||
.duplex = _DUP_INVALID,
|
||||
.port = _NET_DEV_PORT_INVALID,
|
||||
.autonegotiation = -1,
|
||||
.rx_flow_control = -1,
|
||||
.tx_flow_control = -1,
|
||||
.autoneg_flow_control = -1,
|
||||
};
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(link->features); i++)
|
||||
|
@ -409,6 +412,10 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
|
|||
log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
|
||||
}
|
||||
|
||||
r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
|
||||
|
||||
r = sd_device_get_ifindex(device, &ifindex);
|
||||
if (r < 0)
|
||||
return log_device_warning_errno(device, r, "Could not find ifindex: %m");
|
||||
|
|
|
@ -62,6 +62,9 @@ struct link_config {
|
|||
int features[_NET_DEV_FEAT_MAX];
|
||||
netdev_channels channels;
|
||||
netdev_ring_param ring;
|
||||
int rx_flow_control;
|
||||
int tx_flow_control;
|
||||
int autoneg_flow_control;
|
||||
|
||||
LIST_FIELDS(link_config, links);
|
||||
};
|
||||
|
|
|
@ -41,3 +41,6 @@ CombinedChannels=
|
|||
Advertise=
|
||||
RxBufferSize=
|
||||
TxBufferSize=
|
||||
RxFlowControl=
|
||||
TxFlowControl=
|
||||
AutoNegotiationFlowControl=
|
||||
|
|
|
@ -107,6 +107,7 @@ UseDNS=
|
|||
RapidCommit=
|
||||
ForceDHCPv6PDOtherInformation=
|
||||
PrefixDelegationHint=
|
||||
WithoutRA=
|
||||
[Route]
|
||||
Destination=
|
||||
Protocol=
|
||||
|
@ -186,6 +187,7 @@ OnLink=
|
|||
PreferredLifetimeSec=
|
||||
AddressAutoconfiguration=
|
||||
ValidLifetimeSec=
|
||||
Assign=
|
||||
[IPv6RoutePrefix]
|
||||
Route=
|
||||
LifetimeSec=
|
||||
|
@ -249,6 +251,7 @@ Prefix=
|
|||
UseDomains=
|
||||
RouteTable=
|
||||
UseDNS=
|
||||
DHCPv6Client=
|
||||
UseAutonomousPrefix=
|
||||
UseOnLinkPrefix=
|
||||
BlackList=
|
||||
|
@ -326,6 +329,11 @@ TargetSec=
|
|||
IntervalSec=
|
||||
CEThresholdSec=
|
||||
ECN=
|
||||
[CAKE]
|
||||
Parent=
|
||||
Handle=
|
||||
Bandwidth=
|
||||
Overhead=
|
||||
[TrafficControlQueueingDiscipline]
|
||||
Parent=
|
||||
NetworkEmulatorDelaySec=
|
||||
|
@ -337,3 +345,27 @@ NetworkEmulatorPacketLimit=
|
|||
Parent=
|
||||
Handle=
|
||||
Id=
|
||||
[HierarchyTokenBucket]
|
||||
Parent=
|
||||
Handle=
|
||||
DefaultClass=
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=
|
||||
ClassId=
|
||||
Priority=
|
||||
Rate=
|
||||
CeilRate=
|
||||
[PFIFO]
|
||||
Parent=
|
||||
Handle=
|
||||
PacketLimit=
|
||||
[GenericRandomEarlyDetection]
|
||||
Parent=
|
||||
Handle=
|
||||
VirtualQueues=
|
||||
DefaultVirtualQueue=
|
||||
GenericRIO=
|
||||
[StochasticFairBlue]
|
||||
Parent=
|
||||
Handle=
|
||||
PacketLimit=
|
||||
|
|
|
@ -5,7 +5,8 @@ Name=dummy98
|
|||
IPv6AcceptRA=no
|
||||
Address=10.1.2.3/16
|
||||
|
||||
[TrivialLinkEqualizer]
|
||||
[CAKE]
|
||||
Parent=root
|
||||
Handle=0002
|
||||
Id=1
|
||||
Handle=3a
|
||||
Overhead=128
|
||||
Bandwidth=500M
|
|
@ -0,0 +1,162 @@
|
|||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=10.1.2.3/16
|
||||
|
||||
[QDisc]
|
||||
Parent=clsact
|
||||
|
||||
[HierarchyTokenBucket]
|
||||
Parent=root
|
||||
Handle=0002
|
||||
DefaultClass=30
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0030
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[NetworkEmulator]
|
||||
Parent=2:30
|
||||
Handle=0030
|
||||
DelaySec=50ms
|
||||
DelayJitterSec=10ms
|
||||
LossRate=20%
|
||||
PacketLimit=100
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0031
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[TrivialLinkEqualizer]
|
||||
Parent=2:31
|
||||
Handle=0031
|
||||
Id=1
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0032
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[FairQueueing]
|
||||
Parent=2:32
|
||||
Handle=0032
|
||||
PacketLimit=1000
|
||||
FlowLimit=200
|
||||
Quantum=1500
|
||||
InitialQuantum=13000
|
||||
MaximumRate=1M
|
||||
Buckets=512
|
||||
OrphanMask=511
|
||||
Pacing=yes
|
||||
CEThresholdSec=100ms
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0033
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[ControlledDelay]
|
||||
Parent=2:33
|
||||
Handle=0033
|
||||
PacketLimit=2000
|
||||
TargetSec=10ms
|
||||
IntervalSec=50ms
|
||||
ECN=yes
|
||||
CEThresholdSec=100ms
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0034
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[FairQueueingControlledDelay]
|
||||
Parent=2:34
|
||||
Handle=0034
|
||||
PacketLimit=20480
|
||||
MemoryLimit=64M
|
||||
Flows=2048
|
||||
TargetSec=10ms
|
||||
IntervalSec=200ms
|
||||
Quantum=1400
|
||||
ECN=yes
|
||||
CEThresholdSec=100ms
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0035
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[TokenBucketFilter]
|
||||
Parent=2:35
|
||||
Handle=0035
|
||||
Rate=1G
|
||||
Burst=5K
|
||||
LatencySec=70msec
|
||||
PeakRate=100G
|
||||
MTUBytes=1M
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0036
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[StochasticFairnessQueueing]
|
||||
Parent=2:36
|
||||
Handle=0036
|
||||
PerturbPeriodSec=5sec
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0037
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[PFIFO]
|
||||
Parent=2:37
|
||||
Handle=0037
|
||||
PacketLimit=100000
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0038
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[GenericRandomEarlyDetection]
|
||||
Parent=2:38
|
||||
Handle=0038
|
||||
VirtualQueues=12
|
||||
DefaultVirtualQueue=10
|
||||
GenericRIO=yes
|
||||
|
||||
[HierarchyTokenBucketClass]
|
||||
Parent=root
|
||||
ClassId=0002:0039
|
||||
Priority=1
|
||||
Rate=1M
|
||||
CeilRate=0.5M
|
||||
|
||||
[StochasticFairBlue]
|
||||
Parent=2:39
|
||||
Handle=0039
|
||||
PacketLimit=200000
|
|
@ -1,12 +0,0 @@
|
|||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=10.1.2.3/16
|
||||
|
||||
#[TrafficControlQueueingDiscipline]
|
||||
#Parent=root
|
||||
|
||||
[TrafficControlQueueingDiscipline]
|
||||
Parent=clsact
|
|
@ -1,27 +0,0 @@
|
|||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=10.1.2.3/16
|
||||
|
||||
[FairQueueing]
|
||||
Parent=root
|
||||
Handle=0003
|
||||
PacketLimit=1000
|
||||
FlowLimit=200
|
||||
Quantum=1500
|
||||
InitialQuantum=13000
|
||||
MaximumRate=1M
|
||||
Buckets=512
|
||||
OrphanMask=511
|
||||
Pacing=yes
|
||||
CEThresholdSec=100ms
|
||||
|
||||
[ControlledDelay]
|
||||
Parent=clsact
|
||||
PacketLimit=2000
|
||||
TargetSec=10ms
|
||||
IntervalSec=50ms
|
||||
ECN=yes
|
||||
CEThresholdSec=100ms
|
|
@ -1,12 +0,0 @@
|
|||
[Match]
|
||||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=10.1.2.4/16
|
||||
|
||||
#[QDisc]
|
||||
#Parent=root
|
||||
|
||||
[QDisc]
|
||||
Parent=ingress
|
|
@ -1,25 +0,0 @@
|
|||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=10.1.2.3/16
|
||||
|
||||
[NetworkEmulator]
|
||||
Parent=root
|
||||
Handle=001f
|
||||
DelaySec=50ms
|
||||
DelayJitterSec=10ms
|
||||
LossRate=20%
|
||||
PacketLimit=100
|
||||
|
||||
[FairQueueingControlledDelay]
|
||||
Parent=ingress
|
||||
PacketLimit=20480
|
||||
MemoryLimit=64M
|
||||
Flows=2048
|
||||
TargetSec=10ms
|
||||
IntervalSec=200ms
|
||||
Quantum=1400
|
||||
ECN=yes
|
||||
CEThresholdSec=100ms
|
|
@ -1,19 +0,0 @@
|
|||
[Match]
|
||||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=10.1.2.4/16
|
||||
|
||||
[TokenBucketFilter]
|
||||
Parent=root
|
||||
Handle=003f
|
||||
Rate=1G
|
||||
Burst=5K
|
||||
LatencySec=70msec
|
||||
PeakRate=100G
|
||||
MTUBytes=1M
|
||||
|
||||
[StochasticFairnessQueueing]
|
||||
Parent=clsact
|
||||
PerturbPeriodSec=5sec
|
|
@ -4,10 +4,13 @@ Name=veth99
|
|||
[Network]
|
||||
DHCP=no
|
||||
IPv6PrefixDelegation=yes
|
||||
Address=2001:db8:0:1::1/64
|
||||
|
||||
[IPv6Prefix]
|
||||
Prefix=2001:db8:0:1::4/64
|
||||
Prefix=2001:db8:0:1::/64
|
||||
|
||||
[IPv6Prefix]
|
||||
Prefix=2001:db8:0:2::/64
|
||||
Assign=yes
|
||||
|
||||
[IPv6RoutePrefix]
|
||||
Route=2001:db0:fff::/64
|
||||
|
|
|
@ -157,6 +157,18 @@ def expectedFailureIfAlternativeNameIsNotAvailable():
|
|||
|
||||
return f
|
||||
|
||||
def expectedFailureIfCAKEIsNotAvailable():
|
||||
def f(func):
|
||||
call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
|
||||
rc = call('tc qdisc add dev dummy98 parent root cake', stderr=subprocess.DEVNULL)
|
||||
call('ip link del dummy98', stderr=subprocess.DEVNULL)
|
||||
if rc == 0:
|
||||
return func
|
||||
else:
|
||||
return unittest.expectedFailure(func)
|
||||
|
||||
return f
|
||||
|
||||
def setUpModule():
|
||||
global running_units
|
||||
|
||||
|
@ -1621,13 +1633,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
|||
'25-neighbor-ip-dummy.network',
|
||||
'25-neighbor-ip.network',
|
||||
'25-nexthop.network',
|
||||
'25-qdisc-clsact-root-compat.network',
|
||||
'25-qdisc-fq-codel.network',
|
||||
'25-qdisc-cake.network',
|
||||
'25-qdisc-clsact-and-htb.network',
|
||||
'25-qdisc-ingress-netem-compat.network',
|
||||
'25-qdisc-ingress-root.network',
|
||||
'25-qdisc-netem-and-fqcodel.network',
|
||||
'25-qdisc-tbf-and-sfq.network',
|
||||
'25-qdisc-teql.network',
|
||||
'25-route-ipv6-src.network',
|
||||
'25-route-static.network',
|
||||
'25-route-vrf.network',
|
||||
|
@ -2254,71 +2262,85 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
|||
self.assertRegex(output, '192.168.5.1')
|
||||
|
||||
def test_qdisc(self):
|
||||
copy_unit_to_networkd_unit_path('25-qdisc-netem-and-fqcodel.network', '12-dummy.netdev',
|
||||
'25-qdisc-tbf-and-sfq.network', '11-dummy.netdev')
|
||||
start_networkd()
|
||||
|
||||
self.wait_online(['dummy98:routable', 'test1:routable'])
|
||||
|
||||
output = check_output('tc qdisc show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'qdisc netem 1f:')
|
||||
self.assertRegex(output, 'limit 100 delay 50.0ms 10.0ms loss 20%')
|
||||
self.assertRegex(output, 'qdisc fq_codel')
|
||||
self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
|
||||
output = check_output('tc qdisc show dev test1')
|
||||
print(output)
|
||||
self.assertRegex(output, 'qdisc tbf 3f:')
|
||||
self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
|
||||
self.assertRegex(output, 'qdisc sfq')
|
||||
self.assertRegex(output, 'perturb 5sec')
|
||||
|
||||
def test_qdisc2(self):
|
||||
copy_unit_to_networkd_unit_path('25-qdisc-fq-codel.network', '12-dummy.netdev',
|
||||
'25-qdisc-ingress-root.network', '11-dummy.netdev')
|
||||
start_networkd()
|
||||
|
||||
self.wait_online(['dummy98:routable', 'test1:routable'])
|
||||
|
||||
output = check_output('tc qdisc show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'qdisc fq 3:')
|
||||
self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
|
||||
self.assertRegex(output, 'quantum 1500')
|
||||
self.assertRegex(output, 'initial_quantum 13000')
|
||||
self.assertRegex(output, 'maxrate 1Mbit')
|
||||
self.assertRegex(output, 'qdisc codel')
|
||||
self.assertRegex(output, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
|
||||
output = check_output('tc qdisc show dev test1')
|
||||
print(output)
|
||||
self.assertRegex(output, 'qdisc ingress')
|
||||
|
||||
def test_qdisc3(self):
|
||||
copy_unit_to_networkd_unit_path('25-qdisc-clsact-root-compat.network', '12-dummy.netdev',
|
||||
copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
|
||||
'25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
|
||||
check_output('modprobe sch_teql max_equalizers=2')
|
||||
start_networkd()
|
||||
|
||||
self.wait_online(['dummy98:routable', 'test1:routable'])
|
||||
|
||||
output = check_output('tc qdisc show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'qdisc clsact')
|
||||
output = check_output('tc qdisc show dev test1')
|
||||
print(output)
|
||||
self.assertRegex(output, 'qdisc netem')
|
||||
self.assertRegex(output, 'limit 100 delay 50.0ms 10.0ms loss 20%')
|
||||
self.assertRegex(output, 'qdisc ingress')
|
||||
|
||||
def test_qdisc4(self):
|
||||
copy_unit_to_networkd_unit_path('25-qdisc-teql.network', '12-dummy.netdev')
|
||||
check_output('modprobe sch_teql max_equalizers=2')
|
||||
start_networkd()
|
||||
output = check_output('tc qdisc show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'qdisc clsact')
|
||||
|
||||
self.assertRegex(output, 'qdisc htb 2: root')
|
||||
self.assertRegex(output, r'default (0x30|30)')
|
||||
|
||||
self.assertRegex(output, 'qdisc netem 30: parent 2:30')
|
||||
self.assertRegex(output, 'limit 100 delay 50.0ms 10.0ms loss 20%')
|
||||
self.assertRegex(output, 'qdisc fq_codel')
|
||||
self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
|
||||
|
||||
self.assertRegex(output, 'qdisc teql1 31: parent 2:31')
|
||||
|
||||
self.assertRegex(output, 'qdisc fq 32: parent 2:32')
|
||||
self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
|
||||
self.assertRegex(output, 'quantum 1500')
|
||||
self.assertRegex(output, 'initial_quantum 13000')
|
||||
self.assertRegex(output, 'maxrate 1Mbit')
|
||||
|
||||
self.assertRegex(output, 'qdisc codel 33: parent 2:33')
|
||||
self.assertRegex(output, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
|
||||
|
||||
self.assertRegex(output, 'qdisc fq_codel 34: parent 2:34')
|
||||
self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
|
||||
|
||||
self.assertRegex(output, 'qdisc tbf 35: parent 2:35')
|
||||
self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
|
||||
|
||||
self.assertRegex(output, 'qdisc sfq 36: parent 2:36')
|
||||
self.assertRegex(output, 'perturb 5sec')
|
||||
|
||||
self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
|
||||
self.assertRegex(output, 'limit 100000p')
|
||||
|
||||
self.assertRegex(output, 'qdisc gred 38: parent 2:38')
|
||||
self.assertRegex(output, 'vqs 12 default 10 grio')
|
||||
|
||||
self.assertRegex(output, 'qdisc sfb 39: parent 2:39')
|
||||
self.assertRegex(output, 'limit 200000')
|
||||
|
||||
output = check_output('tc class show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'class htb 2:30 root leaf 30:')
|
||||
self.assertRegex(output, 'class htb 2:31 root leaf 31:')
|
||||
self.assertRegex(output, 'class htb 2:32 root leaf 32:')
|
||||
self.assertRegex(output, 'class htb 2:33 root leaf 33:')
|
||||
self.assertRegex(output, 'class htb 2:34 root leaf 34:')
|
||||
self.assertRegex(output, 'class htb 2:35 root leaf 35:')
|
||||
self.assertRegex(output, 'class htb 2:36 root leaf 36:')
|
||||
self.assertRegex(output, 'class htb 2:37 root leaf 37:')
|
||||
self.assertRegex(output, 'class htb 2:38 root leaf 38:')
|
||||
self.assertRegex(output, 'class htb 2:39 root leaf 39:')
|
||||
self.assertRegex(output, 'prio 1 rate 1Mbit ceil 500Kbit')
|
||||
|
||||
@expectedFailureIfCAKEIsNotAvailable()
|
||||
def test_qdisc_cake(self):
|
||||
copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
|
||||
start_networkd()
|
||||
self.wait_online(['dummy98:routable'])
|
||||
|
||||
output = check_output('tc qdisc show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'qdisc teql1 2:')
|
||||
self.assertRegex(output, 'qdisc cake 3a: root')
|
||||
self.assertRegex(output, 'bandwidth 500Mbit')
|
||||
self.assertRegex(output, 'overhead 128')
|
||||
|
||||
class NetworkdStateFileTests(unittest.TestCase, Utilities):
|
||||
links = [
|
||||
|
@ -3591,10 +3613,15 @@ class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
|
|||
start_networkd()
|
||||
self.wait_online(['veth99:routable', 'veth-peer:routable'])
|
||||
|
||||
output = check_output('ip', '-6', 'route', 'show', 'dev', 'veth-peer')
|
||||
output = check_output('ip -6 route show dev veth-peer')
|
||||
print(output)
|
||||
self.assertRegex(output, '2001:db8:0:1::/64 proto ra')
|
||||
|
||||
output = check_output('ip addr show dev veth99')
|
||||
print(output)
|
||||
self.assertNotRegex(output, '2001:db8:0:1')
|
||||
self.assertRegex(output, '2001:db8:0:2')
|
||||
|
||||
class NetworkdMTUTests(unittest.TestCase, Utilities):
|
||||
links = ['dummy98']
|
||||
|
||||
|
|
Loading…
Reference in New Issue