Compare commits

..

18 Commits

Author SHA1 Message Date
Topi Miettinen c3151977d7 namespace: fix MAC labels of /dev when PrivateDevices=yes
Without changing the SELinux label for private /dev of a service, it will take
a generic file system label:
system_u:object_r:tmpfs_t:s0

After this change it is the same as without `PrivateDevices=yes`:
system_u:object_r:device_t:s0

This helps writing SELinux policies, as the same rules for `/dev` will apply
despite any `PrivateDevices=yes` setting.
2020-03-12 08:23:27 +00:00
Yu Watanabe 7bda173f6a
Merge pull request #15084 from yuwata/network-tc-next
network: tc-next take2
2020-03-12 17:17:26 +09:00
Yu Watanabe 970ab1fcc0 test-network: add a test case for HHF 2020-03-12 15:47:03 +09:00
Susant Sahani 7f22402007 network: TC - introduce HHF
Please see https://lwn.net/Articles/577208/
2020-03-12 15:39:12 +09:00
Susant Sahani 7e16f84ea2 sd-netlink: add HHF netlink property 2020-03-12 15:39:12 +09:00
Yu Watanabe 41bb371bb0 test-network: add a test case for PFIFOFast 2020-03-12 15:39:10 +09:00
Susant Sahani 1a95964bfa network: TC - introduce pfifo_fast
pfifo_fast - three-band first in, first out queue

Please see https://linux.die.net/man/8/tc-pfifo_fast
2020-03-12 15:38:18 +09:00
Yu Watanabe 73136507ac test-network: add a test case for PFIFOHeadDrop 2020-03-12 15:38:15 +09:00
Susant Sahani 053a2ddbb2 network: TC - introduce pfifo_head_drop
This adds the required changes to gain access to
the head drop classfull queuing discipline named
pfifo_head_drop.
2020-03-12 15:37:17 +09:00
Yu Watanabe 7b1a31a3d0 test-network: add a test case for BFIFO 2020-03-12 15:37:15 +09:00
Susant Sahani c853f594d4 network: TC - introduce BFIFO
bfifo - Byte limited First In, First Out queue
2020-03-12 15:35:51 +09:00
Yu Watanabe 557fa421ff test-network: add a test case for DRR 2020-03-12 15:35:51 +09:00
Yu Watanabe ad365c5de7 network: tc: introduce DRR class 2020-03-12 15:35:51 +09:00
Susant Sahani f5fc04417e network: TC - introduce DRR
Introduce the Deficit Round Robin Scheduler is a classful queuing discipline as
a more flexible replacement for Stochastic Fairness Queuing.

http://man7.org/linux/man-pages/man8/tc-drr.8.html
2020-03-12 15:35:51 +09:00
Susant Sahani 5c21b46e49 sd-netlink: add DRR netlink properties 2020-03-12 15:35:51 +09:00
Yu Watanabe be94e591fb test-network: add test case for PIE 2020-03-12 15:34:46 +09:00
Susant Sahani bde4ae88c8 network: tc- introduce PIE
Proportional Integral controller-Enhanced (PIE) is a control
theoretic active queue management scheme. It is based on the
proportional integral controller but aims to control delay.

http://man7.org/linux/man-pages/man8/tc-pie.8.html
2020-03-12 13:58:35 +09:00
Susant Sahani 55d228311b sd-netlink: add support for PIE 2020-03-12 13:58:35 +09:00
31 changed files with 944 additions and 19 deletions

View File

@ -2500,6 +2500,38 @@
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>[PIE] Section Options</title>
<para>The <literal>[PIE]</literal> section manages the queueing discipline
(qdisc) of Proportional Integral controller-Enhanced (PIE).</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 1 to 4294967294. Defaults to unset and kernel's default is used.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>[StochasticFairBlue] Section Options</title> <title>[StochasticFairBlue] Section Options</title>
<para>The <literal>[StochasticFairBlue]</literal> section manages the queueing discipline <para>The <literal>[StochasticFairBlue]</literal> section manages the queueing discipline
@ -2565,6 +2597,40 @@
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>[BFIFO] Section Options</title>
<para>The <literal>[BFIFO]</literal> section manages the queueing discipline (qdisc) of
Byte limited Packet First In First Out (bfifo).</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>LimitSize=</varname></term>
<listitem>
<para>Specifies the hard limit on the FIFO size in bytes. 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. When suffixed with K, M, or G, the specified size is parsed as
Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1024. Defaults to unset and kernel's default is used.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>[PFIFO] Section Options</title> <title>[PFIFO] Section Options</title>
<para>The <literal>[PFIFO]</literal> section manages the queueing discipline (qdisc) of <para>The <literal>[PFIFO]</literal> section manages the queueing discipline (qdisc) of
@ -2598,6 +2664,54 @@
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>[PFIFOHeadDrop] Section Options</title>
<para>The <literal>[PFIFOHeadDrop]</literal> section manages the queueing discipline (qdisc) of
Packet First In First Out Head Drop (pfifo_head_drop).</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>Parent=</varname></term>
<listitem>
<para>As in <literal>[PFIFO]</literal> section.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Handle=</varname></term>
<listitem>
<para>As in <literal>[PFIFO]</literal> section..</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PacketLimit=</varname></term>
<listitem>
<para>As in <literal>[PFIFO]</literal> section.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[PFIFOFast] Section Options</title>
<para>The <literal>[PFIFOFast]</literal> section manages the queueing discipline (qdisc) of
Packet First In First Out Fast (pfifo_fast).</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>Parent=</varname></term>
<listitem>
<para>As in <literal>[PFIFO]</literal> section.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Handle=</varname></term>
<listitem>
<para>As in <literal>[PFIFO]</literal> section..</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>[CAKE] Section Options</title> <title>[CAKE] Section Options</title>
<para>The <literal>[CAKE]</literal> section manages the queueing discipline (qdisc) of <para>The <literal>[CAKE]</literal> section manages the queueing discipline (qdisc) of
@ -2707,6 +2821,68 @@
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>[DeficitRoundRobinScheduler] Section Options</title>
<para>The <literal>[DeficitRoundRobinScheduler]</literal> section manages the queueing discipline (qdisc) of
Deficit Round Robin Scheduler (DRR).</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>
</variablelist>
</refsect1>
<refsect1>
<title>[DeficitRoundRobinSchedulerClass] Section Options</title>
<para>The <literal>[DeficitRoundRobinSchedulerClass]</literal> section manages the traffic control class of
Deficit Round Robin Scheduler (DRR).</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>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>Quantum=</varname></term>
<listitem>
<para>Specifies the amount of bytes a flow is allowed to dequeue before the
scheduler moves to the next class. An unsigned integer ranges 1 to 4294967294.
Defaults to the MTU of the interface.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>[GenericRandomEarlyDetection] Section Options</title> <title>[GenericRandomEarlyDetection] Section Options</title>
<para>The <literal>[GenericRandomEarlyDetection]</literal> section manages the queueing discipline <para>The <literal>[GenericRandomEarlyDetection]</literal> section manages the queueing discipline
@ -3070,7 +3246,38 @@
is used.</para> is used.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[HeavyHitterFilter] Section Options</title>
<para>The <literal>[HeavyHitterFilter]</literal> section manages the queueing discipline
(qdisc) of Heavy Hitter Filter (hhf).</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> </variablelist>
</refsect1> </refsect1>

View File

@ -10,11 +10,11 @@
#include "selinux-util.h" #include "selinux-util.h"
#include "smack-util.h" #include "smack-util.h"
int label_fix(const char *path, LabelFixFlags flags) { int label_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
int r, q; int r, q;
r = mac_selinux_fix(path, flags); r = mac_selinux_fix_container(path, inside_path, flags);
q = mac_smack_fix(path, flags); q = mac_smack_fix_container(path, inside_path, flags);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -9,7 +9,10 @@ typedef enum LabelFixFlags {
LABEL_IGNORE_EROFS = 1 << 1, LABEL_IGNORE_EROFS = 1 << 1,
} LabelFixFlags; } LabelFixFlags;
int label_fix(const char *path, LabelFixFlags flags); int label_fix_container(const char *path, const char *inside_path, LabelFixFlags flags);
static inline int label_fix(const char *path, LabelFixFlags flags) {
return label_fix_container(path, path, flags);
}
int mkdir_label(const char *path, mode_t mode); int mkdir_label(const char *path, mode_t mode);
int mkdirat_label(int dirfd, const char *path, mode_t mode); int mkdirat_label(int dirfd, const char *path, mode_t mode);

View File

@ -157,7 +157,7 @@ static int mac_selinux_reload(int seqno) {
} }
#endif #endif
int mac_selinux_fix(const char *path, LabelFixFlags flags) { int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
#if HAVE_SELINUX #if HAVE_SELINUX
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
@ -187,7 +187,7 @@ int mac_selinux_fix(const char *path, LabelFixFlags flags) {
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
(void) avc_netlink_check_nb(); (void) avc_netlink_check_nb();
if (selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode) < 0) { if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) {
r = -errno; r = -errno;
/* If there's no label to set, then exit without warning */ /* If there's no label to set, then exit without warning */
@ -221,7 +221,7 @@ int mac_selinux_fix(const char *path, LabelFixFlags flags) {
return 0; return 0;
fail: fail:
log_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", path); log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path);
if (mac_selinux_enforcing()) if (mac_selinux_enforcing())
return r; return r;
#endif #endif

View File

@ -22,7 +22,11 @@ void mac_selinux_retest(void);
int mac_selinux_init(void); int mac_selinux_init(void);
void mac_selinux_finish(void); void mac_selinux_finish(void);
int mac_selinux_fix(const char *path, LabelFixFlags flags); int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags);
static inline int mac_selinux_fix(const char *path, LabelFixFlags flags) {
return mac_selinux_fix_container(path, path, flags);
}
int mac_selinux_apply(const char *path, const char *label); int mac_selinux_apply(const char *path, const char *label);
int mac_selinux_get_create_label_from_exe(const char *exe, char **label); int mac_selinux_get_create_label_from_exe(const char *exe, char **label);

View File

@ -206,7 +206,7 @@ int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags) {
return smack_fix_fd(fd, path, flags); return smack_fix_fd(fd, path, flags);
} }
int mac_smack_fix(const char *path, LabelFixFlags flags) { int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
_cleanup_free_ char *abspath = NULL; _cleanup_free_ char *abspath = NULL;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
int r; int r;
@ -228,7 +228,7 @@ int mac_smack_fix(const char *path, LabelFixFlags flags) {
return -errno; return -errno;
} }
return smack_fix_fd(fd, abspath, flags); return smack_fix_fd(fd, inside_path, flags);
} }
int mac_smack_copy(const char *dest, const char *src) { int mac_smack_copy(const char *dest, const char *src) {
@ -274,7 +274,7 @@ int mac_smack_apply_pid(pid_t pid, const char *label) {
return 0; return 0;
} }
int mac_smack_fix(const char *path, LabelFixFlags flags) { int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
return 0; return 0;
} }

View File

@ -29,7 +29,11 @@ typedef enum SmackAttr {
bool mac_smack_use(void); bool mac_smack_use(void);
int mac_smack_fix(const char *path, LabelFixFlags flags); int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags);
static inline int mac_smack_fix(const char *path, LabelFixFlags flags) {
return mac_smack_fix_container(path, path, flags);
}
int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags); int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags);
const char* smack_attr_to_string(SmackAttr i) _const_; const char* smack_attr_to_string(SmackAttr i) _const_;

View File

@ -690,6 +690,11 @@ static int mount_private_dev(MountEntry *m) {
r = log_debug_errno(errno, "Failed to mount tmpfs on '%s': %m", dev); r = log_debug_errno(errno, "Failed to mount tmpfs on '%s': %m", dev);
goto fail; goto fail;
} }
r = label_fix_container(dev, "/dev", 0);
if (r < 0) {
log_debug_errno(errno, "Failed to fix label of '%s' as /dev: %m", dev);
goto fail;
}
devpts = strjoina(temporary_mount, "/dev/pts"); devpts = strjoina(temporary_mount, "/dev/pts");
(void) mkdir(devpts, 0755); (void) mkdir(devpts, 0755);

View File

@ -760,6 +760,10 @@ static const NLType rtnl_tca_option_data_codel_types[] = {
[TCA_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, [TCA_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 },
}; };
static const NLType rtnl_tca_option_data_drr_types[] = {
[TCA_DRR_QUANTUM] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_fq_types[] = { static const NLType rtnl_tca_option_data_fq_types[] = {
[TCA_FQ_PLIMIT] = { .type = NETLINK_TYPE_U32 }, [TCA_FQ_PLIMIT] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_FLOW_PLIMIT] = { .type = NETLINK_TYPE_U32 }, [TCA_FQ_FLOW_PLIMIT] = { .type = NETLINK_TYPE_U32 },
@ -791,6 +795,10 @@ static const NLType rtnl_tca_option_data_gred_types[] = {
[TCA_GRED_DPS] = { .size = sizeof(struct tc_gred_sopt) }, [TCA_GRED_DPS] = { .size = sizeof(struct tc_gred_sopt) },
}; };
static const NLType rtnl_tca_option_data_hhf_types[] = {
[TCA_HHF_BACKLOG_LIMIT] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_htb_types[] = { static const NLType rtnl_tca_option_data_htb_types[] = {
[TCA_HTB_PARMS] = { .size = sizeof(struct tc_htb_opt) }, [TCA_HTB_PARMS] = { .size = sizeof(struct tc_htb_opt) },
[TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) }, [TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) },
@ -800,6 +808,10 @@ static const NLType rtnl_tca_option_data_htb_types[] = {
[TCA_HTB_CEIL64] = { .type = NETLINK_TYPE_U64 }, [TCA_HTB_CEIL64] = { .type = NETLINK_TYPE_U64 },
}; };
static const NLType rtnl_tca_option_data_pie_types[] = {
[TCA_PIE_LIMIT] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_sfb_types[] = { static const NLType rtnl_tca_option_data_sfb_types[] = {
[TCA_SFB_PARMS] = { .size = sizeof(struct tc_sfb_qopt) }, [TCA_SFB_PARMS] = { .size = sizeof(struct tc_sfb_qopt) },
}; };
@ -817,10 +829,13 @@ static const NLType rtnl_tca_option_data_tbf_types[] = {
static const char* const nl_union_tca_option_data_table[] = { static const char* const nl_union_tca_option_data_table[] = {
[NL_UNION_TCA_OPTION_DATA_CAKE] = "cake", [NL_UNION_TCA_OPTION_DATA_CAKE] = "cake",
[NL_UNION_TCA_OPTION_DATA_CODEL] = "codel", [NL_UNION_TCA_OPTION_DATA_CODEL] = "codel",
[NL_UNION_TCA_OPTION_DATA_DRR] = "drr",
[NL_UNION_TCA_OPTION_DATA_FQ] = "fq", [NL_UNION_TCA_OPTION_DATA_FQ] = "fq",
[NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = "fq_codel", [NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = "fq_codel",
[NL_UNION_TCA_OPTION_DATA_GRED] = "gred", [NL_UNION_TCA_OPTION_DATA_GRED] = "gred",
[NL_UNION_TCA_OPTION_DATA_HHF] = "hhf",
[NL_UNION_TCA_OPTION_DATA_HTB] = "htb", [NL_UNION_TCA_OPTION_DATA_HTB] = "htb",
[NL_UNION_TCA_OPTION_DATA_PIE] = "pie",
[NL_UNION_TCA_OPTION_DATA_SFB] = "sfb", [NL_UNION_TCA_OPTION_DATA_SFB] = "sfb",
[NL_UNION_TCA_OPTION_DATA_TBF] = "tbf", [NL_UNION_TCA_OPTION_DATA_TBF] = "tbf",
}; };
@ -832,14 +847,20 @@ static const NLTypeSystem rtnl_tca_option_data_type_systems[] = {
.types = 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), [NL_UNION_TCA_OPTION_DATA_CODEL] = { .count = ELEMENTSOF(rtnl_tca_option_data_codel_types),
.types = rtnl_tca_option_data_codel_types }, .types = rtnl_tca_option_data_codel_types },
[NL_UNION_TCA_OPTION_DATA_DRR] = { .count = ELEMENTSOF(rtnl_tca_option_data_drr_types),
.types = rtnl_tca_option_data_drr_types },
[NL_UNION_TCA_OPTION_DATA_FQ] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_types), [NL_UNION_TCA_OPTION_DATA_FQ] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_types),
.types = 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), [NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_codel_types),
.types = 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), [NL_UNION_TCA_OPTION_DATA_GRED] = { .count = ELEMENTSOF(rtnl_tca_option_data_gred_types),
.types = rtnl_tca_option_data_gred_types }, .types = rtnl_tca_option_data_gred_types },
[NL_UNION_TCA_OPTION_DATA_HHF] = { .count = ELEMENTSOF(rtnl_tca_option_data_hhf_types),
.types = rtnl_tca_option_data_hhf_types },
[NL_UNION_TCA_OPTION_DATA_HTB] = { .count = ELEMENTSOF(rtnl_tca_option_data_htb_types), [NL_UNION_TCA_OPTION_DATA_HTB] = { .count = ELEMENTSOF(rtnl_tca_option_data_htb_types),
.types = rtnl_tca_option_data_htb_types }, .types = rtnl_tca_option_data_htb_types },
[NL_UNION_TCA_OPTION_DATA_PIE] = { .count = ELEMENTSOF(rtnl_tca_option_data_pie_types),
.types = rtnl_tca_option_data_pie_types },
[NL_UNION_TCA_OPTION_DATA_SFB] = { .count = ELEMENTSOF(rtnl_tca_option_data_sfb_types), [NL_UNION_TCA_OPTION_DATA_SFB] = { .count = ELEMENTSOF(rtnl_tca_option_data_sfb_types),
.types = 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), [NL_UNION_TCA_OPTION_DATA_TBF] = { .count = ELEMENTSOF(rtnl_tca_option_data_tbf_types),

View File

@ -98,10 +98,13 @@ NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_;
typedef enum NLUnionTCAOptionData { typedef enum NLUnionTCAOptionData {
NL_UNION_TCA_OPTION_DATA_CAKE, NL_UNION_TCA_OPTION_DATA_CAKE,
NL_UNION_TCA_OPTION_DATA_CODEL, NL_UNION_TCA_OPTION_DATA_CODEL,
NL_UNION_TCA_OPTION_DATA_DRR,
NL_UNION_TCA_OPTION_DATA_FQ, NL_UNION_TCA_OPTION_DATA_FQ,
NL_UNION_TCA_OPTION_DATA_FQ_CODEL, NL_UNION_TCA_OPTION_DATA_FQ_CODEL,
NL_UNION_TCA_OPTION_DATA_GRED, NL_UNION_TCA_OPTION_DATA_GRED,
NL_UNION_TCA_OPTION_DATA_HHF,
NL_UNION_TCA_OPTION_DATA_HTB, NL_UNION_TCA_OPTION_DATA_HTB,
NL_UNION_TCA_OPTION_DATA_PIE,
NL_UNION_TCA_OPTION_DATA_SFB, NL_UNION_TCA_OPTION_DATA_SFB,
NL_UNION_TCA_OPTION_DATA_TBF, NL_UNION_TCA_OPTION_DATA_TBF,
_NL_UNION_TCA_OPTION_DATA_MAX, _NL_UNION_TCA_OPTION_DATA_MAX,

View File

@ -111,6 +111,8 @@ sources = files('''
tc/cake.h tc/cake.h
tc/codel.c tc/codel.c
tc/codel.h tc/codel.h
tc/drr.c
tc/drr.h
tc/fifo.c tc/fifo.c
tc/fifo.h tc/fifo.h
tc/fq.c tc/fq.c
@ -119,10 +121,14 @@ sources = files('''
tc/fq-codel.h tc/fq-codel.h
tc/gred.c tc/gred.c
tc/gred.h tc/gred.h
tc/hhf.c
tc/hhf.h
tc/htb.c tc/htb.c
tc/htb.h tc/htb.h
tc/netem.c tc/netem.c
tc/netem.h tc/netem.h
tc/pie.c
tc/pie.h
tc/qdisc.c tc/qdisc.c
tc/qdisc.h tc/qdisc.h
tc/sfb.c tc/sfb.c

View File

@ -258,6 +258,9 @@ CAN.TripleSampling, config_parse_tristate,
CAN.Termination, config_parse_tristate, 0, offsetof(Network, can_termination) CAN.Termination, config_parse_tristate, 0, offsetof(Network, can_termination)
QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0 QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0
QDisc.Handle, config_parse_qdisc_handle, _QDISC_KIND_INVALID, 0 QDisc.Handle, config_parse_qdisc_handle, _QDISC_KIND_INVALID, 0
BFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_BFIFO, 0
BFIFO.Handle, config_parse_qdisc_handle, QDISC_KIND_BFIFO, 0
BFIFO.LimitSize, config_parse_bfifo_size, QDISC_KIND_BFIFO, 0
CAKE.Parent, config_parse_qdisc_parent, QDISC_KIND_CAKE, 0 CAKE.Parent, config_parse_qdisc_parent, QDISC_KIND_CAKE, 0
CAKE.Handle, config_parse_qdisc_handle, 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.Bandwidth, config_parse_cake_bandwidth, QDISC_KIND_CAKE, 0
@ -269,9 +272,19 @@ ControlledDelay.TargetSec, config_parse_controlled_delay_usec,
ControlledDelay.IntervalSec, config_parse_controlled_delay_usec, QDISC_KIND_CODEL, 0 ControlledDelay.IntervalSec, config_parse_controlled_delay_usec, QDISC_KIND_CODEL, 0
ControlledDelay.CEThresholdSec, 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 ControlledDelay.ECN, config_parse_controlled_delay_bool, QDISC_KIND_CODEL, 0
DeficitRoundRobinScheduler.Parent, config_parse_qdisc_parent, QDISC_KIND_DRR, 0
DeficitRoundRobinScheduler.Handle, config_parse_qdisc_handle, QDISC_KIND_DRR, 0
DeficitRoundRobinSchedulerClass.Parent, config_parse_tclass_parent, TCLASS_KIND_DRR, 0
DeficitRoundRobinSchedulerClass.ClassId, config_parse_tclass_classid, TCLASS_KIND_DRR, 0
DeficitRoundRobinSchedulerClass.Quantum, config_parse_drr_size, TCLASS_KIND_DRR, 0
PFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO, 0 PFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO, 0
PFIFO.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO, 0 PFIFO.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO, 0
PFIFO.PacketLimit, config_parse_fifo_size, QDISC_KIND_PFIFO, 0 PFIFO.PacketLimit, config_parse_pfifo_size, QDISC_KIND_PFIFO, 0
PFIFOFast.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO_FAST, 0
PFIFOFast.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO_FAST, 0
PFIFOHeadDrop.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO_HEAD_DROP, 0
PFIFOHeadDrop.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO_HEAD_DROP, 0
PFIFOHeadDrop.PacketLimit, config_parse_pfifo_size, QDISC_KIND_PFIFO_HEAD_DROP, 0
FairQueueing.Parent, config_parse_qdisc_parent, QDISC_KIND_FQ, 0 FairQueueing.Parent, config_parse_qdisc_parent, QDISC_KIND_FQ, 0
FairQueueing.Handle, config_parse_qdisc_handle, 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 FairQueueing.PacketLimit, config_parse_fair_queueing_u32, QDISC_KIND_FQ, 0
@ -298,6 +311,9 @@ GenericRandomEarlyDetection.Handle, config_parse_qdisc_handle,
GenericRandomEarlyDetection.VirtualQueues, config_parse_generic_random_early_detection_u32, 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.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 GenericRandomEarlyDetection.GenericRIO, config_parse_generic_random_early_detection_bool, QDISC_KIND_GRED, 0
HeavyHitterFilter.Parent, config_parse_qdisc_parent, QDISC_KIND_HHF, 0
HeavyHitterFilter.Handle, config_parse_qdisc_handle, QDISC_KIND_HHF, 0
HeavyHitterFilter.PacketLimit, config_parse_heavy_hitter_filter_packet_limit, QDISC_KIND_HHF, 0
HierarchyTokenBucket.Parent, config_parse_qdisc_parent, QDISC_KIND_HTB, 0 HierarchyTokenBucket.Parent, config_parse_qdisc_parent, QDISC_KIND_HTB, 0
HierarchyTokenBucket.Handle, config_parse_qdisc_handle, 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 HierarchyTokenBucket.DefaultClass, config_parse_hierarchy_token_bucket_default_class, QDISC_KIND_HTB, 0
@ -313,6 +329,9 @@ NetworkEmulator.DelayJitterSec, config_parse_network_emulator_delay
NetworkEmulator.LossRate, config_parse_network_emulator_rate, QDISC_KIND_NETEM, 0 NetworkEmulator.LossRate, config_parse_network_emulator_rate, QDISC_KIND_NETEM, 0
NetworkEmulator.DuplicateRate, 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 NetworkEmulator.PacketLimit, config_parse_network_emulator_packet_limit, QDISC_KIND_NETEM, 0
PIE.Parent, config_parse_qdisc_parent, QDISC_KIND_PIE, 0
PIE.Handle, config_parse_qdisc_handle, QDISC_KIND_PIE, 0
PIE.PacketLimit, config_parse_pie_packet_limit, QDISC_KIND_PIE, 0
StochasticFairBlue.Parent, config_parse_qdisc_parent, QDISC_KIND_SFB, 0 StochasticFairBlue.Parent, config_parse_qdisc_parent, QDISC_KIND_SFB, 0
StochasticFairBlue.Handle, config_parse_qdisc_handle, 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 StochasticFairBlue.PacketLimit, config_parse_stochastic_fair_blue_u32, QDISC_KIND_SFB, 0

View File

@ -486,15 +486,22 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
"TrafficControlQueueingDiscipline\0" "TrafficControlQueueingDiscipline\0"
"CAN\0" "CAN\0"
"QDisc\0" "QDisc\0"
"BFIFO\0"
"CAKE\0" "CAKE\0"
"ControlledDelay\0" "ControlledDelay\0"
"DeficitRoundRobinScheduler\0"
"DeficitRoundRobinSchedulerClass\0"
"PFIFO\0" "PFIFO\0"
"PFIFOFast\0"
"PFIFOHeadDrop\0"
"FairQueueing\0" "FairQueueing\0"
"FairQueueingControlledDelay\0" "FairQueueingControlledDelay\0"
"GenericRandomEarlyDetection\0" "GenericRandomEarlyDetection\0"
"HeavyHitterFilter\0"
"HierarchyTokenBucket\0" "HierarchyTokenBucket\0"
"HierarchyTokenBucketClass\0" "HierarchyTokenBucketClass\0"
"NetworkEmulator\0" "NetworkEmulator\0"
"PIE\0"
"StochasticFairBlue\0" "StochasticFairBlue\0"
"StochasticFairnessQueueing\0" "StochasticFairnessQueueing\0"
"TokenBucketFilter\0" "TokenBucketFilter\0"

105
src/network/tc/drr.c Normal file
View File

@ -0,0 +1,105 @@
/* SPDX-License-Identifier: LGPL-2.1+
* Copyright © 2020 VMware, Inc. */
#include <linux/pkt_sched.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "drr.h"
#include "netlink-util.h"
#include "parse-util.h"
#include "string-util.h"
const QDiscVTable drr_vtable = {
.object_size = sizeof(DeficitRoundRobinScheduler),
.tca_kind = "drr",
};
static int drr_class_fill_message(Link *link, TClass *tclass, sd_netlink_message *req) {
DeficitRoundRobinSchedulerClass *drr;
int r;
assert(link);
assert(tclass);
assert(req);
drr = TCLASS_TO_DRR(tclass);
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "drr");
if (r < 0)
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
if (drr->quantum > 0) {
r = sd_netlink_message_append_u32(req, TCA_DRR_QUANTUM, drr->quantum);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_DRR_QUANTUM, 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_drr_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_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
DeficitRoundRobinSchedulerClass *drr;
Network *network = data;
uint64_t u;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = tclass_new_static(TCLASS_KIND_DRR, 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");
drr = TCLASS_TO_DRR(tclass);
if (isempty(rvalue)) {
drr->quantum = 0;
tclass = NULL;
return 0;
}
r = parse_size(rvalue, 1000, &u);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
if (u > UINT32_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
drr->quantum = (uint32_t) u;
tclass = NULL;
return 0;
}
const TClassVTable drr_tclass_vtable = {
.object_size = sizeof(DeficitRoundRobinSchedulerClass),
.tca_kind = "drr",
.fill_message = drr_class_fill_message,
};

23
src/network/tc/drr.h Normal file
View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: LGPL-2.1+
* Copyright © 2020 VMware, Inc. */
#pragma once
#include "qdisc.h"
typedef struct DeficitRoundRobinScheduler {
QDisc meta;
} DeficitRoundRobinScheduler;
DEFINE_QDISC_CAST(DRR, DeficitRoundRobinScheduler);
extern const QDiscVTable drr_vtable;
typedef struct DeficitRoundRobinSchedulerClass {
TClass meta;
uint32_t quantum;
} DeficitRoundRobinSchedulerClass;
DEFINE_TCLASS_CAST(DRR, DeficitRoundRobinSchedulerClass);
extern const TClassVTable drr_tclass_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_drr_size);

View File

@ -19,7 +19,19 @@ static int fifo_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req)
assert(qdisc); assert(qdisc);
assert(req); assert(req);
fifo = PFIFO(qdisc); switch(qdisc->kind) {
case QDISC_KIND_PFIFO:
fifo = PFIFO(qdisc);
break;
case QDISC_KIND_BFIFO:
fifo = BFIFO(qdisc);
break;
case QDISC_KIND_PFIFO_HEAD_DROP:
fifo = PFIFO_HEAD_DROP(qdisc);
break;
default:
assert_not_reached("Invalid QDisc kind.");
}
opt.limit = fifo->limit; opt.limit = fifo->limit;
@ -30,7 +42,7 @@ static int fifo_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req)
return 0; return 0;
} }
int config_parse_fifo_size( int config_parse_pfifo_size(
const char *unit, const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
@ -52,14 +64,23 @@ int config_parse_fifo_size(
assert(rvalue); assert(rvalue);
assert(data); assert(data);
r = qdisc_new_static(QDISC_KIND_PFIFO, network, filename, section_line, &qdisc); r = qdisc_new_static(ltype, network, filename, section_line, &qdisc);
if (r == -ENOMEM) if (r == -ENOMEM)
return log_oom(); return log_oom();
if (r < 0) if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r, return log_syntax(unit, LOG_ERR, filename, line, r,
"More than one kind of queueing discipline, ignoring assignment: %m"); "More than one kind of queueing discipline, ignoring assignment: %m");
fifo = PFIFO(qdisc); switch(qdisc->kind) {
case QDISC_KIND_PFIFO:
fifo = PFIFO(qdisc);
break;
case QDISC_KIND_PFIFO_HEAD_DROP:
fifo = PFIFO_HEAD_DROP(qdisc);
break;
default:
assert_not_reached("Invalid QDisc kind.");
}
if (isempty(rvalue)) { if (isempty(rvalue)) {
fifo->limit = 0; fifo->limit = 0;
@ -80,8 +101,83 @@ int config_parse_fifo_size(
return 0; return 0;
} }
int config_parse_bfifo_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;
uint64_t u;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(QDISC_KIND_BFIFO, 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 = BFIFO(qdisc);
if (isempty(rvalue)) {
fifo->limit = 0;
qdisc = NULL;
return 0;
}
r = parse_size(rvalue, 1000, &u);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
if (u > UINT32_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
fifo->limit = (uint32_t) u;
qdisc = NULL;
return 0;
}
const QDiscVTable pfifo_vtable = { const QDiscVTable pfifo_vtable = {
.object_size = sizeof(FirstInFirstOut), .object_size = sizeof(FirstInFirstOut),
.tca_kind = "pfifo", .tca_kind = "pfifo",
.fill_message = fifo_fill_message, .fill_message = fifo_fill_message,
}; };
const QDiscVTable bfifo_vtable = {
.object_size = sizeof(FirstInFirstOut),
.tca_kind = "bfifo",
.fill_message = fifo_fill_message,
};
const QDiscVTable pfifo_head_drop_vtable = {
.object_size = sizeof(FirstInFirstOut),
.tca_kind = "pfifo_head_drop",
.fill_message = fifo_fill_message,
};
const QDiscVTable pfifo_fast_vtable = {
.object_size = sizeof(FirstInFirstOut),
.tca_kind = "pfifo_fast",
};

View File

@ -12,6 +12,14 @@ typedef struct FirstInFirstOut {
} FirstInFirstOut; } FirstInFirstOut;
DEFINE_QDISC_CAST(PFIFO, FirstInFirstOut); DEFINE_QDISC_CAST(PFIFO, FirstInFirstOut);
extern const QDiscVTable pfifo_vtable; DEFINE_QDISC_CAST(BFIFO, FirstInFirstOut);
DEFINE_QDISC_CAST(PFIFO_HEAD_DROP, FirstInFirstOut);
DEFINE_QDISC_CAST(PFIFO_FAST, FirstInFirstOut);
CONFIG_PARSER_PROTOTYPE(config_parse_fifo_size); extern const QDiscVTable pfifo_vtable;
extern const QDiscVTable bfifo_vtable;
extern const QDiscVTable pfifo_head_drop_vtable;
extern const QDiscVTable pfifo_fast_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_pfifo_size);
CONFIG_PARSER_PROTOTYPE(config_parse_bfifo_size);

96
src/network/tc/hhf.c Normal file
View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: LGPL-2.1+
* Copyright © 2020 VMware, Inc. */
#include <linux/pkt_sched.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "hhf.h"
#include "netlink-util.h"
#include "parse-util.h"
#include "string-util.h"
#include "util.h"
static int heavy_hitter_filter_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
HeavyHitterFilter *hhf;
int r;
assert(link);
assert(qdisc);
assert(req);
hhf = HHF(qdisc);
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "hhf");
if (r < 0)
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
if (hhf->packet_limit > 0) {
r = sd_netlink_message_append_u32(req, TCA_HHF_BACKLOG_LIMIT, hhf->packet_limit);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_HHF_BACKLOG_LIMIT 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_heavy_hitter_filter_packet_limit(
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;
HeavyHitterFilter *hhf;
Network *network = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(QDISC_KIND_HHF, 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");
hhf = HHF(qdisc);
if (isempty(rvalue)) {
hhf->packet_limit = 0;
qdisc = NULL;
return 0;
}
r = safe_atou32(rvalue, &hhf->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 hhf_vtable = {
.object_size = sizeof(HeavyHitterFilter),
.tca_kind = "hhf",
.fill_message = heavy_hitter_filter_fill_message,
};

17
src/network/tc/hhf.h Normal file
View File

@ -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 HeavyHitterFilter {
QDisc meta;
uint32_t packet_limit;
} HeavyHitterFilter;
DEFINE_QDISC_CAST(HHF, HeavyHitterFilter);
extern const QDiscVTable hhf_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_heavy_hitter_filter_packet_limit);

95
src/network/tc/pie.c Normal file
View File

@ -0,0 +1,95 @@
/* SPDX-License-Identifier: LGPL-2.1+
* Copyright © 2020 VMware, Inc. */
#include <linux/pkt_sched.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "pie.h"
#include "netlink-util.h"
#include "parse-util.h"
#include "string-util.h"
static int pie_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
proportional_integral_controller_enhanced *pie;
int r;
assert(link);
assert(qdisc);
assert(req);
pie = PIE(qdisc);
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "pie");
if (r < 0)
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
if (pie->packet_limit > 0) {
r = sd_netlink_message_append_u32(req, TCA_PIE_LIMIT, pie->packet_limit);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_PIE_PLIMIT 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_pie_packet_limit(
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;
proportional_integral_controller_enhanced *pie;
Network *network = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(QDISC_KIND_PIE, 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");
pie = PIE(qdisc);
if (isempty(rvalue)) {
pie->packet_limit = 0;
qdisc = NULL;
return 0;
}
r = safe_atou32(rvalue, &pie->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 pie_vtable = {
.object_size = sizeof(proportional_integral_controller_enhanced),
.tca_kind = "pie",
.fill_message = pie_fill_message,
};

17
src/network/tc/pie.h Normal file
View File

@ -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 proportional_integral_controller_enhanced {
QDisc meta;
uint32_t packet_limit;
} proportional_integral_controller_enhanced;
DEFINE_QDISC_CAST(PIE, proportional_integral_controller_enhanced);
extern const QDiscVTable pie_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_pie_packet_limit);

View File

@ -16,14 +16,20 @@
#include "tc-util.h" #include "tc-util.h"
const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = { const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
[QDISC_KIND_BFIFO] = &bfifo_vtable,
[QDISC_KIND_CAKE] = &cake_vtable, [QDISC_KIND_CAKE] = &cake_vtable,
[QDISC_KIND_CODEL] = &codel_vtable, [QDISC_KIND_CODEL] = &codel_vtable,
[QDISC_KIND_DRR] = &drr_vtable,
[QDISC_KIND_FQ] = &fq_vtable, [QDISC_KIND_FQ] = &fq_vtable,
[QDISC_KIND_FQ_CODEL] = &fq_codel_vtable, [QDISC_KIND_FQ_CODEL] = &fq_codel_vtable,
[QDISC_KIND_GRED] = &gred_vtable, [QDISC_KIND_GRED] = &gred_vtable,
[QDISC_KIND_HHF] = &hhf_vtable,
[QDISC_KIND_HTB] = &htb_vtable, [QDISC_KIND_HTB] = &htb_vtable,
[QDISC_KIND_NETEM] = &netem_vtable, [QDISC_KIND_NETEM] = &netem_vtable,
[QDISC_KIND_PIE] = &pie_vtable,
[QDISC_KIND_PFIFO] = &pfifo_vtable, [QDISC_KIND_PFIFO] = &pfifo_vtable,
[QDISC_KIND_PFIFO_FAST] = &pfifo_fast_vtable,
[QDISC_KIND_PFIFO_HEAD_DROP] = &pfifo_head_drop_vtable,
[QDISC_KIND_SFB] = &sfb_vtable, [QDISC_KIND_SFB] = &sfb_vtable,
[QDISC_KIND_SFQ] = &sfq_vtable, [QDISC_KIND_SFQ] = &sfq_vtable,
[QDISC_KIND_TBF] = &tbf_vtable, [QDISC_KIND_TBF] = &tbf_vtable,

View File

@ -9,14 +9,20 @@
#include "tc.h" #include "tc.h"
typedef enum QDiscKind { typedef enum QDiscKind {
QDISC_KIND_BFIFO,
QDISC_KIND_CAKE, QDISC_KIND_CAKE,
QDISC_KIND_CODEL, QDISC_KIND_CODEL,
QDISC_KIND_DRR,
QDISC_KIND_FQ, QDISC_KIND_FQ,
QDISC_KIND_FQ_CODEL, QDISC_KIND_FQ_CODEL,
QDISC_KIND_GRED, QDISC_KIND_GRED,
QDISC_KIND_HHF,
QDISC_KIND_HTB, QDISC_KIND_HTB,
QDISC_KIND_NETEM, QDISC_KIND_NETEM,
QDISC_KIND_PFIFO, QDISC_KIND_PFIFO,
QDISC_KIND_PFIFO_FAST,
QDISC_KIND_PFIFO_HEAD_DROP,
QDISC_KIND_PIE,
QDISC_KIND_SFB, QDISC_KIND_SFB,
QDISC_KIND_SFQ, QDISC_KIND_SFQ,
QDISC_KIND_TBF, QDISC_KIND_TBF,
@ -84,8 +90,11 @@ CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_handle);
#include "fq-codel.h" #include "fq-codel.h"
#include "fq.h" #include "fq.h"
#include "gred.h" #include "gred.h"
#include "hhf.h"
#include "htb.h" #include "htb.h"
#include "pie.h"
#include "netem.h" #include "netem.h"
#include "drr.h"
#include "sfb.h" #include "sfb.h"
#include "sfq.h" #include "sfq.h"
#include "tbf.h" #include "tbf.h"

View File

@ -16,6 +16,7 @@
#include "tclass.h" #include "tclass.h"
const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX] = { const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX] = {
[TCLASS_KIND_DRR] = &drr_tclass_vtable,
[TCLASS_KIND_HTB] = &htb_tclass_vtable, [TCLASS_KIND_HTB] = &htb_tclass_vtable,
}; };

View File

@ -9,6 +9,7 @@
#include "tc.h" #include "tc.h"
typedef enum TClassKind { typedef enum TClassKind {
TCLASS_KIND_DRR,
TCLASS_KIND_HTB, TCLASS_KIND_HTB,
_TCLASS_KIND_MAX, _TCLASS_KIND_MAX,
_TCLASS_KIND_INVALID = -1, _TCLASS_KIND_INVALID = -1,
@ -64,4 +65,5 @@ DEFINE_TC_CAST(TCLASS, TClass);
CONFIG_PARSER_PROTOTYPE(config_parse_tclass_parent); CONFIG_PARSER_PROTOTYPE(config_parse_tclass_parent);
CONFIG_PARSER_PROTOTYPE(config_parse_tclass_classid); CONFIG_PARSER_PROTOTYPE(config_parse_tclass_classid);
#include "drr.h"
#include "htb.h" #include "htb.h"

View File

@ -356,10 +356,21 @@ ClassId=
Priority= Priority=
Rate= Rate=
CeilRate= CeilRate=
[BFIFO]
Parent=
Handle=
LimitSize=
[PFIFO] [PFIFO]
Parent= Parent=
Handle= Handle=
PacketLimit= PacketLimit=
[PFIFOHeadDrop]
Parent=
Handle=
PacketLimit=
[PFIFOFast]
Parent=
Handle=
[GenericRandomEarlyDetection] [GenericRandomEarlyDetection]
Parent= Parent=
Handle= Handle=
@ -370,3 +381,18 @@ GenericRIO=
Parent= Parent=
Handle= Handle=
PacketLimit= PacketLimit=
[PIE]
Parent=
Handle=
PacketLimit=
[DeficitRoundRobinScheduler]
Parent=
Handle=
[DeficitRoundRobinSchedulerClass]
Parent=
ClassId=
Quantum=
[HeavyHitterFilter]
Parent=
Handle=
PacketLimit=

View File

@ -160,3 +160,38 @@ CeilRate=0.5M
Parent=2:39 Parent=2:39
Handle=0039 Handle=0039
PacketLimit=200000 PacketLimit=200000
[HierarchyTokenBucketClass]
Parent=root
ClassId=0002:003a
Priority=1
Rate=1M
CeilRate=0.5M
[BFIFO]
Parent=2:3a
Handle=003a
LimitSize=1M
[HierarchyTokenBucketClass]
Parent=root
ClassId=0002:003b
Priority=1
Rate=1M
CeilRate=0.5M
[PFIFOHeadDrop]
Parent=2:3b
Handle=003b
PacketLimit=1023
[HierarchyTokenBucketClass]
Parent=root
ClassId=0002:003c
Priority=1
Rate=1M
CeilRate=0.5M
[PFIFOFast]
Parent=2:3c
Handle=003c

View File

@ -0,0 +1,15 @@
[Match]
Name=dummy98
[Network]
IPv6AcceptRA=no
Address=10.1.2.3/16
[DeficitRoundRobinScheduler]
Parent=root
Handle=0002
[DeficitRoundRobinSchedulerClass]
Parent=root
ClassId=0002:0030
Quantum=2000

View File

@ -0,0 +1,11 @@
[Match]
Name=dummy98
[Network]
IPv6AcceptRA=no
Address=10.1.2.3/16
[HeavyHitterFilter]
Parent=root
Handle=3a
PacketLimit=1022

View File

@ -0,0 +1,11 @@
[Match]
Name=dummy98
[Network]
IPv6AcceptRA=no
Address=10.1.2.3/16
[PIE]
Parent=root
Handle=3a
PacketLimit=200000

View File

@ -169,6 +169,30 @@ def expectedFailureIfCAKEIsNotAvailable():
return f return f
def expectedFailureIfPIEIsNotAvailable():
def f(func):
call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
rc = call('tc qdisc add dev dummy98 parent root pie', stderr=subprocess.DEVNULL)
call('ip link del dummy98', stderr=subprocess.DEVNULL)
if rc == 0:
return func
else:
return unittest.expectedFailure(func)
return f
def expectedFailureIfHHFIsNotAvailable():
def f(func):
call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
rc = call('tc qdisc add dev dummy98 parent root hhf', 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(): def setUpModule():
global running_units global running_units
@ -1635,7 +1659,10 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'25-nexthop.network', '25-nexthop.network',
'25-qdisc-cake.network', '25-qdisc-cake.network',
'25-qdisc-clsact-and-htb.network', '25-qdisc-clsact-and-htb.network',
'25-qdisc-drr.network',
'25-qdisc-hhf.network',
'25-qdisc-ingress-netem-compat.network', '25-qdisc-ingress-netem-compat.network',
'25-qdisc-pie.network',
'25-route-ipv6-src.network', '25-route-ipv6-src.network',
'25-route-static.network', '25-route-static.network',
'25-route-vrf.network', '25-route-vrf.network',
@ -2316,6 +2343,14 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'qdisc sfb 39: parent 2:39') self.assertRegex(output, 'qdisc sfb 39: parent 2:39')
self.assertRegex(output, 'limit 200000') self.assertRegex(output, 'limit 200000')
self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
self.assertRegex(output, 'limit 1000000')
self.assertRegex(output, 'qdisc pfifo_head_drop 3b: parent 2:3b')
self.assertRegex(output, 'limit 1023p')
self.assertRegex(output, 'qdisc pfifo_fast 3c: parent 2:3c')
output = check_output('tc class show dev dummy98') output = check_output('tc class show dev dummy98')
print(output) print(output)
self.assertRegex(output, 'class htb 2:30 root leaf 30:') self.assertRegex(output, 'class htb 2:30 root leaf 30:')
@ -2328,8 +2363,24 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'class htb 2:37 root leaf 37:') 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:38 root leaf 38:')
self.assertRegex(output, 'class htb 2:39 root leaf 39:') self.assertRegex(output, 'class htb 2:39 root leaf 39:')
self.assertRegex(output, 'class htb 2:3a root leaf 3a:')
self.assertRegex(output, 'class htb 2:3b root leaf 3b:')
self.assertRegex(output, 'class htb 2:3c root leaf 3c:')
self.assertRegex(output, 'prio 1 rate 1Mbit ceil 500Kbit') self.assertRegex(output, 'prio 1 rate 1Mbit ceil 500Kbit')
def test_qdisc2(self):
copy_unit_to_networkd_unit_path('25-qdisc-drr.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 drr 2: root')
output = check_output('tc class show dev dummy98')
print(output)
self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
@expectedFailureIfCAKEIsNotAvailable() @expectedFailureIfCAKEIsNotAvailable()
def test_qdisc_cake(self): def test_qdisc_cake(self):
copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev') copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
@ -2342,6 +2393,28 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'bandwidth 500Mbit') self.assertRegex(output, 'bandwidth 500Mbit')
self.assertRegex(output, 'overhead 128') self.assertRegex(output, 'overhead 128')
@expectedFailureIfPIEIsNotAvailable()
def test_qdisc_pie(self):
copy_unit_to_networkd_unit_path('25-qdisc-pie.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 pie 3a: root')
self.assertRegex(output, 'limit 200000')
@expectedFailureIfHHFIsNotAvailable()
def test_qdisc_hhf(self):
copy_unit_to_networkd_unit_path('25-qdisc-hhf.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 hhf 3a: root')
self.assertRegex(output, 'limit 1022p')
class NetworkdStateFileTests(unittest.TestCase, Utilities): class NetworkdStateFileTests(unittest.TestCase, Utilities):
links = [ links = [
'dummy98', 'dummy98',