632 lines
18 KiB
Diff
Executable File
632 lines
18 KiB
Diff
Executable File
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
|
|
index 07f00fa..de9382d 100644
|
|
--- a/include/netlink-private/types.h
|
|
+++ b/include/netlink-private/types.h
|
|
@@ -626,6 +626,20 @@ struct rtnl_sfq
|
|
uint32_t qs_mask;
|
|
};
|
|
|
|
+struct rtnl_sfb
|
|
+{
|
|
+ uint32_t qsb_rehash_interval;
|
|
+ uint32_t qsb_warmup_time;
|
|
+ uint32_t qsb_limit;
|
|
+ uint32_t qsb_target;
|
|
+ uint32_t qsb_max;
|
|
+ uint32_t qsb_increment;
|
|
+ uint32_t qsb_decrement;
|
|
+ uint32_t qsb_penalty_rate;
|
|
+ uint32_t qsb_penalty_burst;
|
|
+ uint32_t qsb_mask;
|
|
+};
|
|
+
|
|
struct rtnl_netem_corr
|
|
{
|
|
uint32_t nmc_delay;
|
|
diff --git a/include/netlink/route/qdisc/sfb.h b/include/netlink/route/qdisc/sfb.h
|
|
new file mode 100644
|
|
index 0000000..2899ab2
|
|
--- /dev/null
|
|
+++ b/include/netlink/route/qdisc/sfb.h
|
|
@@ -0,0 +1,60 @@
|
|
+/*
|
|
+ * netlink/route/sch/sfb.c SFB Qdisc
|
|
+ */
|
|
+/*
|
|
+ **************************************************************************
|
|
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
|
+ * Permission to use, copy, modify, and/or distribute this software for
|
|
+ * any purpose with or without fee is hereby granted, provided that the
|
|
+ * above copyright notice and this permission notice appear in all copies.
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
+ **************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef NETLINK_SFB_H_
|
|
+#define NETLINK_SFB_H_
|
|
+
|
|
+#include <netlink/netlink.h>
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+extern void rtnl_sfb_set_rehash_interval(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_rehash_interval(struct rtnl_qdisc *);
|
|
+
|
|
+extern void rtnl_sfb_set_warmup_time(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_warmup_time(struct rtnl_qdisc *);
|
|
+
|
|
+extern void rtnl_sfb_set_max(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_max(struct rtnl_qdisc *);
|
|
+
|
|
+extern void rtnl_sfb_set_bin_size(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_bin_size(struct rtnl_qdisc *);
|
|
+
|
|
+extern void rtnl_sfb_set_increment(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_increment(struct rtnl_qdisc *);
|
|
+
|
|
+extern void rtnl_sfb_set_decrement(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_decrement(struct rtnl_qdisc *);
|
|
+
|
|
+extern void rtnl_sfb_set_limit(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_limit(struct rtnl_qdisc *);
|
|
+
|
|
+extern void rtnl_sfb_set_penalty_rate(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_penalty_rate(struct rtnl_qdisc *);
|
|
+
|
|
+extern void rtnl_sfb_set_penalty_burst(struct rtnl_qdisc *, int);
|
|
+extern int rtnl_sfq_get_penalty_burst(struct rtnl_qdisc *);
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif
|
|
diff --git a/lib/Makefile.am b/lib/Makefile.am
|
|
index b619198..a1b5ddb 100644
|
|
--- a/lib/Makefile.am
|
|
+++ b/lib/Makefile.am
|
|
@@ -79,6 +79,7 @@ libnl_route_3_la_SOURCES = \
|
|
route/qdisc/codel.c \
|
|
route/qdisc/hfsc.c \
|
|
route/qdisc/drr.c \
|
|
+ route/qdisc/sfb.c \
|
|
\
|
|
fib_lookup/lookup.c fib_lookup/request.c \
|
|
\
|
|
diff --git a/lib/route/qdisc/sfb.c b/lib/route/qdisc/sfb.c
|
|
new file mode 100644
|
|
index 0000000..015e6a2
|
|
--- /dev/null
|
|
+++ b/lib/route/qdisc/sfb.c
|
|
@@ -0,0 +1,522 @@
|
|
+/*
|
|
+ * lib/route/qdisc/sfb.c Stochastic Fair Blue Qdisc
|
|
+ */
|
|
+/*
|
|
+ **************************************************************************
|
|
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
|
+ * Permission to use, copy, modify, and/or distribute this software for
|
|
+ * any purpose with or without fee is hereby granted, provided that the
|
|
+ * above copyright notice and this permission notice appear in all copies.
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
+ **************************************************************************
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * @ingroup qdisc
|
|
+ * @defgroup qdisc_sfb Stochastic Fair Blue (SFB)
|
|
+ * @brief
|
|
+ * Sch_sfb is an implementation of the Stochastic Fair Blue (SFB) queue
|
|
+ * management algorithm for Linux.
|
|
+ *
|
|
+ * SFB aims to keep your queues short while avoiding packet drops,
|
|
+ * maximising link utilisation and preserving fairness between flows.
|
|
+ * SFB will detect flows that do not respond to congestion indications,
|
|
+ * and limit them to a constant share of the link's capacity.
|
|
+ *
|
|
+ * SFB only deals with marking and/or droping packets. Reordering of
|
|
+ * packets is handled by sfb's child qdisc; by default, this is pfifo,
|
|
+ * meaning that no reordering will happen. You may want to use something
|
|
+ * like prio or sfq as sfb's child.
|
|
+ *
|
|
+ * Unlike most other fair queueing policies, SFB doesn't actually keep
|
|
+ * per-flow state; it manages flow information using a Bloom filter,
|
|
+ * which means that hash collisions are reduced to a minimum while using
|
|
+ * fairly little memory.
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+#include <netlink-private/netlink.h>
|
|
+#include <netlink-private/tc.h>
|
|
+#include <netlink/netlink.h>
|
|
+#include <netlink/utils.h>
|
|
+#include <netlink-private/route/tc-api.h>
|
|
+#include <netlink/route/qdisc.h>
|
|
+#include <netlink/route/qdisc/sfb.h>
|
|
+
|
|
+/** @cond SKIP */
|
|
+#define SCH_SFB_ATTR_REHASH 0x001
|
|
+#define SCH_SFB_ATTR_WARMUP 0x002
|
|
+#define SCH_SFB_ATTR_LIMIT 0x004
|
|
+#define SCH_SFB_ATTR_TARGET 0x008
|
|
+#define SCH_SFB_ATTR_MAX 0x010
|
|
+#define SCH_SFB_ATTR_INCREMENT 0x020
|
|
+#define SCH_SFB_ATTR_DECREMENT 0x040
|
|
+#define SCH_SFB_ATTR_PEN_RATE 0x080
|
|
+#define SCH_SFB_ATTR_PEN_BURST 0x100
|
|
+/** @endcond */
|
|
+
|
|
+static int sfb_msg_parser(struct rtnl_tc *tc, void *data)
|
|
+{
|
|
+ struct rtnl_sfb *sfb = data;
|
|
+ struct tc_sfb_qopt *opts;
|
|
+
|
|
+ if (!(tc->ce_mask & TCA_ATTR_OPTS))
|
|
+ return 0;
|
|
+
|
|
+ if (tc->tc_opts->d_size < sizeof(*opts))
|
|
+ return -NLE_INVAL;
|
|
+
|
|
+ opts = (struct tc_sfb_qopt *) tc->tc_opts->d_data;
|
|
+
|
|
+ sfb->qsb_rehash_interval = opts->rehash_interval;
|
|
+ sfb->qsb_warmup_time = opts->warmup_time;
|
|
+ sfb->qsb_limit = opts->limit;
|
|
+ sfb->qsb_target = opts->bin_size;
|
|
+ sfb->qsb_max = opts->max;
|
|
+ sfb->qsb_increment = opts->increment;
|
|
+ sfb->qsb_decrement = opts->decrement;
|
|
+ sfb->qsb_penalty_rate = opts->penalty_rate;
|
|
+ sfb->qsb_penalty_burst = opts->penalty_burst;
|
|
+
|
|
+ sfb->qsb_mask = (SCH_SFB_ATTR_REHASH | SCH_SFB_ATTR_WARMUP |
|
|
+ SCH_SFB_ATTR_LIMIT | SCH_SFB_ATTR_MAX |
|
|
+ SCH_SFB_ATTR_TARGET |
|
|
+ SCH_SFB_ATTR_INCREMENT | SCH_SFB_ATTR_DECREMENT |
|
|
+ SCH_SFB_ATTR_PEN_RATE | SCH_SFB_ATTR_PEN_BURST);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void sfb_dump_line(struct rtnl_tc *tc, void *data,
|
|
+ struct nl_dump_params *p)
|
|
+{
|
|
+ struct rtnl_sfb *sfb = data;
|
|
+
|
|
+ if (sfb)
|
|
+ nl_dump(p, " limit %u target %u max %u" ,
|
|
+ sfb->qsb_limit, sfb->qsb_target, sfb->qsb_max);
|
|
+}
|
|
+
|
|
+static void sfb_dump_details(struct rtnl_tc *tc, void *data,
|
|
+ struct nl_dump_params *p)
|
|
+{
|
|
+ struct rtnl_sfb *sfb = data;
|
|
+
|
|
+ if (sfb)
|
|
+ nl_dump(p, "rehash_interval %us warmup_time %us "
|
|
+ "increment %u decrement %u "
|
|
+ "penalty_rate %up/s penalty_burst %up",
|
|
+ sfb->qsb_rehash_interval, sfb->qsb_warmup_time,
|
|
+ sfb->qsb_increment, sfb->qsb_decrement,
|
|
+ sfb->qsb_penalty_rate, sfb->qsb_penalty_burst);
|
|
+}
|
|
+
|
|
+static int sfb_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
|
|
+{
|
|
+ struct rtnl_sfb *sfb = data;
|
|
+ struct tc_sfb_qopt opts = {0};
|
|
+
|
|
+ if (!sfb)
|
|
+ BUG();
|
|
+
|
|
+ opts.rehash_interval = sfb->qsb_rehash_interval;
|
|
+ opts.warmup_time = sfb->qsb_warmup_time;
|
|
+ opts.limit = sfb->qsb_limit;
|
|
+ opts.bin_size = sfb->qsb_target;
|
|
+ opts.max = sfb->qsb_max;
|
|
+ opts.increment = sfb->qsb_increment;
|
|
+ opts.decrement = sfb->qsb_decrement;
|
|
+ opts.penalty_rate = sfb->qsb_penalty_rate;
|
|
+ opts.penalty_burst = sfb->qsb_penalty_burst;
|
|
+
|
|
+ return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @name Attribute Access
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Set the rehash interval of SFB qdisc.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg interval_secs Specifies how often, in seconds, before we will switch
|
|
+ * to a fresh Bloom filter and a different set of hash functions. Since Bloom
|
|
+ * filters are more resistent to hash collisions that hash tables, this may be
|
|
+ * set to a fairly large value.
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_rehash_interval(struct rtnl_qdisc *qdisc, int interval_secs)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_rehash_interval = interval_secs;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_REHASH;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get rehash interval of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Rehash interval in seconds, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_rehash_interval(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_REHASH)
|
|
+ return sfb->qsb_rehash_interval;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Set the warmup time of SFB qdisc.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg warmup_secs In seconds, how long we will perform double buffering
|
|
+ * before switching to a new bloom filter. This should be long enough to make
|
|
+ * sure that the new filter is ``primed'' before it is used, a few tens of
|
|
+ * seconds should be enough.
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_warmup_time(struct rtnl_qdisc *qdisc, int warmup_secs)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_warmup_time = warmup_secs;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_WARMUP;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get warmup time of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Warmup time in seconds, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_warmup_time(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_WARMUP)
|
|
+ return sfb->qsb_warmup_time;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Set the total packet limit of SFB qdisc.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg interval The hard limit on the number of packets in all of sfb's
|
|
+ * aggregates (total qdisc limit). Set it to some large value, it should never
|
|
+ * be reached anyway.
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_limit(struct rtnl_qdisc *qdisc, int interval)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_limit = interval;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_REHASH;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get rehash interval of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Limit in packets, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_limit(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_REHASH)
|
|
+ return sfb->qsb_limit;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Set the target number of packets per aggregate of SFB qdisc.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg target_packets the target per-flow queue size in packets. sfb will
|
|
+ * try to keep each per-aggregate queue between 0 and target.
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_target_packets(struct rtnl_qdisc *qdisc, int target_packets)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_target = target_packets;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_TARGET;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get rehash interval of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Target packets per aggregate, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_target_packets(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_TARGET)
|
|
+ return sfb->qsb_target;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Set the max packets per aggregate of SFB qdisc.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg max_packets The maximum number of packets queued for a given
|
|
+ * aggregate. It should be very slightly larger than target, in order to
|
|
+ * absorb transient bursts. Setting this to more than roughly 1.5 times target
|
|
+ * will cause instabilities with which Blue is not designed to cope.
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_max_packets(struct rtnl_qdisc *qdisc, int max_packets)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_max = max_packets;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_MAX;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get max packets per aggregate of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Max packets, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_max_packets(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_MAX)
|
|
+ return sfb->qsb_max;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Set the underflow increment of SFB qdisc.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg increment 16-bit fixed point integer that represents the value by
|
|
+ * which per-flow dropping probability is decreased on queue underflow. This
|
|
+ * should be a small fraction of a percent, and increment should be a few times
|
|
+ * smaller than decrement.
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_underflow_increment(struct rtnl_qdisc *qdisc, int increment)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_increment = increment;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_INCREMENT;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get underflow increment of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Underflow increment in 16-bit fixed point, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_underflow_increment(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_INCREMENT)
|
|
+ return sfb->qsb_increment;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Set the overflow decrement of SFB qdisc.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg decrement 16-bit fixed point integer that represents the value by
|
|
+ * which per-flow dropping probability is increased on queue overflow. This
|
|
+ * should be a small fraction of a percent, and decrement should be a few times
|
|
+ * larger than increment.
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_overflow_decrement(struct rtnl_qdisc *qdisc, int decrement)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_decrement = decrement;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_DECREMENT;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get overflow decrement of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Overflow decrement in 16-bit fixed point, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_overflow_decrement(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_DECREMENT)
|
|
+ return sfb->qsb_decrement;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Set the penalty rate of SFB qdisc.
|
|
+ *
|
|
+ * When a flow doesn't back off in response to congestion indication, sfb will
|
|
+ * categorise it as ``non-reactive'' and will rate-limit it.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg packets_per_sec Total throughput that non-reactive flows are allowed to
|
|
+ * use in packets per second. You should set penalty_rate to some reasonable
|
|
+ * fraction of your up-link throughput (the default values are probably too
|
|
+ * small).
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_penalty_rate(struct rtnl_qdisc *qdisc, int packets_per_sec)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_penalty_rate = packets_per_sec;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_PEN_RATE;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get the penalty rate of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Penalty rate in packets per second, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_penalty_rate(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_PEN_RATE)
|
|
+ return sfb->qsb_penalty_rate;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Set the penalty burst of SFB qdisc.
|
|
+ *
|
|
+ * When a flow doesn't back off in response to congestion indication, sfb will
|
|
+ * categorise it as ``non-reactive'' and will rate-limit it.
|
|
+ *
|
|
+ * @arg qdisc SFB qdisc to be modified.
|
|
+ * @arg burst_packets Number of packets in the token bucket for penalty rate
|
|
+ * limiting.
|
|
+ * @return 0 on success or a negative error code.
|
|
+ */
|
|
+void rtnl_sfb_set_penalty_burst(struct rtnl_qdisc *qdisc, int burst_packets)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ sfb->qsb_penalty_burst = burst_packets;
|
|
+ sfb->qsb_mask |= SCH_SFB_ATTR_PEN_BURST;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Get the penalty burst of SFB qdisc.
|
|
+ * @arg qdisc SFB qdisc.
|
|
+ * @return Penalty burst size in packets, or a negative error code.
|
|
+ */
|
|
+int rtnl_sfb_get_penalty_burst(struct rtnl_qdisc *qdisc)
|
|
+{
|
|
+ struct rtnl_sfb *sfb;
|
|
+
|
|
+ if (!(sfb = rtnl_tc_data(TC_CAST(qdisc))))
|
|
+ BUG();
|
|
+
|
|
+ if (sfb->qsb_mask & SCH_SFB_ATTR_PEN_RATE)
|
|
+ return sfb->qsb_penalty_burst;
|
|
+ else
|
|
+ return -NLE_NOATTR;
|
|
+}
|
|
+
|
|
+/** @} */
|
|
+
|
|
+static struct rtnl_tc_ops sfb_ops = {
|
|
+ .to_kind = "sfb",
|
|
+ .to_type = RTNL_TC_TYPE_QDISC,
|
|
+ .to_size = sizeof(struct rtnl_sfb),
|
|
+ .to_msg_parser = sfb_msg_parser,
|
|
+ .to_dump = {
|
|
+ [NL_DUMP_LINE] = sfb_dump_line,
|
|
+ [NL_DUMP_DETAILS] = sfb_dump_details,
|
|
+ },
|
|
+ .to_msg_fill = sfb_msg_fill,
|
|
+};
|
|
+
|
|
+static void __init sfb_init(void)
|
|
+{
|
|
+ rtnl_tc_register(&sfb_ops);
|
|
+}
|
|
+
|
|
+static void __exit sfb_exit(void)
|
|
+{
|
|
+ rtnl_tc_unregister(&sfb_ops);
|
|
+}
|
|
+
|
|
+/** @} */
|