1
1
Files
zyxel-vmg8825_b50b-cfw/package/libs/libnl/patches-3.2.21/0007-Add-nssqdisc-support.patch
T
2026-04-17 18:33:03 +02:00

2007 lines
53 KiB
Diff
Executable File

diff --git a/include/Makefile.am b/include/Makefile.am
index c5e0a90..7b8f0bd 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -59,6 +59,11 @@ nobase_libnlinclude_HEADERS = \
netlink/route/qdisc/codel.h \
netlink/route/qdisc/fq_codel.h \
netlink/route/qdisc/plug.h \
+ netlink/route/qdisc/nssbf.h \
+ netlink/route/qdisc/nsscodel.h \
+ netlink/route/qdisc/nssfifo.h \
+ netlink/route/qdisc/nssprio.h \
+ netlink/route/qdisc/nsstbl.h \
netlink/route/addr.h \
netlink/route/class.h \
netlink/route/classifier.h \
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index fdc441a..4eb702a 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -755,5 +755,96 @@ struct tc_bf_xstats {
#define TCA_BF_MAX (__TCA_BF_MAX - 1)
+/* NSSFIFO section */
+
+enum {
+ TCA_NSSFIFO_UNSPEC,
+ TCA_NSSFIFO_PARMS,
+ __TCA_NSSFIFO_MAX
+};
+
+#define TCA_NSSFIFO_MAX (__TCA_NSSFIFO_MAX - 1)
+
+struct tc_nssfifo_qopt {
+ __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */
+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */
+};
+
+/* NSSCODEL section */
+
+enum {
+ TCA_NSSCODEL_UNSPEC,
+ TCA_NSSCODEL_PARMS,
+ __TCA_NSSCODEL_MAX
+};
+
+#define TCA_NSSCODEL_MAX (__TCA_NSSCODEL_MAX - 1)
+
+struct tc_nsscodel_qopt {
+ __u32 target; /* Acceptable queueing delay */
+ __u32 limit; /* Maximum number of packets that can be held in the queue */
+ __u32 interval; /* Monitoring interval */
+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */
+};
+
+struct tc_nsscodel_xstats {
+ __u32 peak_queue_delay; /* Peak delay experienced by a dequeued packet */
+ __u32 peak_drop_delay; /* Peak delay experienced by a dropped packet */
+};
+
+/* NSSTBL section */
+
+enum {
+ TCA_NSSTBL_UNSPEC,
+ TCA_NSSTBL_PARMS,
+ __TCA_NSSTBL_MAX
+};
+
+#define TCA_NSSTBL_MAX (__TCA_NSSTBL_MAX - 1)
+
+struct tc_nsstbl_qopt {
+ __u32 burst; /* Maximum burst size */
+ __u32 rate; /* Limiting rate of TBF */
+ __u32 peakrate; /* Maximum rate at which TBF is allowed to send */
+ __u32 mtu; /* Max size of packet, or minumim burst size */
+};
+
+/* NSSPRIO section */
+
+#define TCA_NSSPRIO_MAX_BANDS 256
+
+enum {
+ TCA_NSSPRIO_UNSPEC,
+ TCA_NSSPRIO_PARMS,
+ __TCA_NSSPRIO_MAX
+};
+
+#define TCA_NSSPRIO_MAX (__TCA_NSSPRIO_MAX - 1)
+
+struct tc_nssprio_qopt {
+ int bands; /* Number of bands */
+};
+
+/* NSSBF section */
+
+enum {
+ TCA_NSSBF_UNSPEC,
+ TCA_NSSBF_CLASS_PARMS,
+ TCA_NSSBF_QDISC_PARMS,
+ __TCA_NSSBF_MAX
+};
+
+#define TCA_NSSBF_MAX (__TCA_NSSBF_MAX - 1)
+
+struct tc_nssbf_class_qopt {
+ __u32 burst; /* Maximum burst size */
+ __u32 rate; /* Allowed bandwidth for this class */
+ __u32 mtu; /* MTU of attached interface */
+ __u32 quantum; /* Quantum allocation value for DRR */
+};
+
+struct tc_nssbf_qopt {
+ __u16 defcls; /* Default class value */
+};
#endif
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
index fe97fa4..42eb07f 100644
--- a/include/netlink-private/types.h
+++ b/include/netlink-private/types.h
@@ -659,6 +659,47 @@ struct rtnl_sfb
uint32_t qsb_mask;
};
+struct rtnl_nssfifo
+{
+ uint32_t qpf_limit;
+ uint32_t qpf_mask;
+ uint8_t qpf_set_default;
+};
+
+struct rtnl_nsscodel {
+ uint32_t anf_target;
+ uint32_t anf_limit;
+ uint32_t anf_interval;
+ uint32_t anf_mask;
+ uint8_t anf_set_default;
+};
+
+struct rtnl_nsstbl {
+ uint32_t ias_rate;
+ uint32_t ias_burst;
+ uint32_t ias_peakrate;
+ uint32_t ias_mtu;
+ uint32_t ias_mask;
+};
+
+struct rtnl_nssprio {
+ int agj_bands;
+ uint32_t agj_mask;
+};
+
+struct rtnl_nssbf_class {
+ uint32_t ery_burst;
+ uint32_t ery_rate;
+ uint32_t ery_mtu;
+ uint32_t ery_quantum;
+ uint32_t ery_mask;
+};
+
+struct rtnl_nssbf_qdisc {
+ uint16_t awv_defcls;
+ uint32_t awv_mask;
+};
+
struct rtnl_netem_corr
{
uint32_t nmc_delay;
diff --git a/include/netlink/route/qdisc/nssbf.h b/include/netlink/route/qdisc/nssbf.h
new file mode 100644
index 0000000..3d03126
--- /dev/null
+++ b/include/netlink/route/qdisc/nssbf.h
@@ -0,0 +1,49 @@
+/*
+ * netlink/route/sch/nssbf.h NSSBF 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_NSSBF_H_
+#define NETLINK_NSSBF_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_nssbf_qdisc_set_defcls(struct rtnl_qdisc *qdisc, uint16_t defcls);
+extern uint32_t rtnl_nssbf_qdisc_get_defcls(struct rtnl_qdisc *qdisc);
+
+extern int rtnl_nssbf_class_set_rate(struct rtnl_class *class, uint32_t rate);
+extern uint32_t rtnl_nssbf_class_get_rate(struct rtnl_class *class);
+
+extern int rtnl_nssbf_class_set_burst(struct rtnl_class *class, uint32_t burst);
+extern uint32_t rtnl_nssbf_class_get_burst(struct rtnl_class *class);
+
+extern int rtnl_nssbf_class_set_mtu(struct rtnl_class *class, uint32_t mtu);
+extern uint32_t rtnl_nssbf_class_get_mtu(struct rtnl_class *class);
+
+extern int rtnl_nssbf_class_set_quantum(struct rtnl_class *class, uint32_t q);
+extern uint32_t rtnl_nssbf_class_get_quantum(struct rtnl_class *class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/nsscodel.h b/include/netlink/route/qdisc/nsscodel.h
new file mode 100644
index 0000000..331032b
--- /dev/null
+++ b/include/netlink/route/qdisc/nsscodel.h
@@ -0,0 +1,46 @@
+/*
+ * netlink/route/sch/nsscodel.h NSSCODEL 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_NSSCODEL_H_
+#define NETLINK_NSSCODEL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_nsscodel_set_limit(struct rtnl_qdisc *qdisc, uint32_t limit);
+extern uint32_t rtnl_nsscodel_get_limit(struct rtnl_qdisc *qdisc);
+
+extern int rtnl_nsscodel_set_target(struct rtnl_qdisc *qdisc, uint32_t target);
+extern uint32_t rtnl_nsscodel_get_target(struct rtnl_qdisc *qdisc);
+
+extern int rtnl_nsscodel_set_interval(struct rtnl_qdisc *qdisc, uint32_t interval);
+extern uint32_t rtnl_nsscodel_get_interval(struct rtnl_qdisc *qdisc);
+
+extern int rtnl_nsscodel_set_default(struct rtnl_qdisc *qdisc, uint8_t set_default);
+extern uint8_t rtnl_nsscodel_get_default(struct rtnl_qdisc *qdisc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/nssfifo.h b/include/netlink/route/qdisc/nssfifo.h
new file mode 100644
index 0000000..37e6475
--- /dev/null
+++ b/include/netlink/route/qdisc/nssfifo.h
@@ -0,0 +1,40 @@
+/*
+ * netlink/route/sch/nssfifo.c NSSFIFO 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_NSSFIFO_H_
+#define NETLINK_NSSFIFO_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_nssfifo_set_limit(struct rtnl_qdisc *, uint32_t);
+extern uint32_t rtnl_nssfifo_get_limit(struct rtnl_qdisc *);
+
+extern int rtnl_nssfifo_set_default(struct rtnl_qdisc *, uint8_t);
+extern uint8_t rtnl_nssfifo_get_default(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/nssprio.h b/include/netlink/route/qdisc/nssprio.h
new file mode 100644
index 0000000..39296d8
--- /dev/null
+++ b/include/netlink/route/qdisc/nssprio.h
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/sch/nssprio.h NSSPRIO 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_NSSPRIO_H_
+#define NETLINK_NSSPRIO_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_nssprio_set_bands(struct rtnl_qdisc *qdisc, int bands);
+extern int rtnl_nssprio_get_bands(struct rtnl_qdisc *qdisc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/nsstbl.h b/include/netlink/route/qdisc/nsstbl.h
new file mode 100644
index 0000000..c896540
--- /dev/null
+++ b/include/netlink/route/qdisc/nsstbl.h
@@ -0,0 +1,46 @@
+/*
+ * netlink/route/sch/nsstbl.h NSSTBL 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_NSSTBL_H_
+#define NETLINK_NSSTBL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_nsstbl_set_rate(struct rtnl_qdisc *qdisc, uint32_t rate);
+extern uint32_t rtnl_nsstbl_get_rate(struct rtnl_qdisc *qdisc);
+
+extern int rtnl_nsstbl_set_burst(struct rtnl_qdisc *qdisc, uint32_t burst);
+extern uint32_t rtnl_nsstbl_get_burst(struct rtnl_qdisc *qdisc);
+
+extern int rtnl_nsstbl_set_mtu(struct rtnl_qdisc *qdisc, uint32_t mtu);
+extern uint32_t rtnl_nsstbl_get_mtu(struct rtnl_qdisc *qdisc);
+
+extern int rtnl_nsstbl_set_peakrate(struct rtnl_qdisc *qdisc, uint32_t peakrate);
+extern uint32_t rtnl_nsstbl_get_peakrate(struct rtnl_qdisc *qdisc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
index c6f5639..8891a0f 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -81,6 +81,8 @@ libnl_route_3_la_SOURCES = \
route/qdisc/drr.c \
route/qdisc/sfb.c \
route/qdisc/bf.c \
+ route/qdisc/nssfifo.c route/qdisc/nsstbl.c route/qdisc/nssbf.c \
+ route/qdisc/nssprio.c route/qdisc/nsscodel.c \
\
fib_lookup/lookup.c fib_lookup/request.c \
\
@@ -113,6 +115,7 @@ nobase_pkglib_LTLIBRARIES = \
cli/qdisc/pfifo.la \
cli/qdisc/plug.la \
cli/qdisc/bfifo.la \
+ cli/qdisc/nsspfifo.la \
cli/cls/basic.la \
cli/cls/cgroup.la
@@ -123,6 +126,7 @@ cli_qdisc_blackhole_la_LDFLAGS = -module -avoid-version
cli_qdisc_pfifo_la_LDFLAGS = -module -avoid-version
cli_qdisc_plug_la_LDFLAGS = -module -avoid-version
cli_qdisc_bfifo_la_LDFLAGS = -module -avoid-version
+cli_qdisc_nsspfifo_la_LDFLAGS = -module -avoid-version
cli_cls_basic_la_LDFLAGS = -module -avoid-version
cli_cls_cgroup_la_LDFLAGS = -module -avoid-version
endif
diff --git a/lib/cli/qdisc/nsspfifo.c b/lib/cli/qdisc/nsspfifo.c
new file mode 100644
index 0000000..b9d3cf8
--- /dev/null
+++ b/lib/cli/qdisc/nsspfifo.c
@@ -0,0 +1,92 @@
+/*
+ * src/lib/nsspfifo.c nsspfifo module for CLI lib
+ */
+/*
+ **************************************************************************
+ * 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.
+ **************************************************************************
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/nssfifo.h>
+
+static void print_usage(void)
+{
+ printf(
+"Usage: nl-qdisc-add [...] nsspfifo [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+" --help Show this help text.\n"
+" --limit=LIMIT Maximum queue length in number of packets.\n"
+" --set_default Set, if this needs to be the default enqueue node.\n"
+"\n"
+"EXAMPLE"
+" # Attach nsspfifo with a 32 packet limit to eth1, and set as default\n"
+" nl-qdisc-add --dev=eth1 --parent=root nsspfifo --limit=32 --set_default\n");
+}
+
+static void nsspfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+ struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+ rtnl_qdisc_nssfifo_set_set_default(qdisc, 0);
+ for (;;) {
+ int c, optidx = 0;
+ enum {
+ ARG_LIMIT = 257,
+ ARG_SET_DEFAULT = 258,
+ };
+ static struct option long_opts[] = {
+ { "help", 0, 0, 'h' },
+ { "limit", 1, 0, ARG_LIMIT },
+ { "set_default", 1, 0, ARG_SET_DEFAULT },
+ { 0, 0, 0, 0 }
+ };
+
+ c = getopt_long(argc, argv, "h", long_opts, &optidx);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage();
+ return;
+
+ case ARG_LIMIT:
+ rtnl_qdisc_nssfifo_set_limit(qdisc, nl_cli_parse_u32(optarg));
+ break;
+
+ case ARG_SET_DEFAULT:
+ rtnl_qdisc_nssfifo_set_set_default(qdisc, 1);
+ break;
+ }
+ }
+}
+
+static struct nl_cli_tc_module nsspfifo_module =
+{
+ .tm_name = "nsspfifo",
+ .tm_type = RTNL_TC_TYPE_QDISC,
+ .tm_parse_argv = nsspfifo_parse_argv,
+};
+
+static void __init nsspfifo_init(void)
+{
+ nl_cli_tc_register(&nsspfifo_module);
+}
+
+static void __exit nsspfifo_exit(void)
+{
+ nl_cli_tc_unregister(&nsspfifo_module);
+}
diff --git a/lib/route/qdisc/nssbf.c b/lib/route/qdisc/nssbf.c
new file mode 100644
index 0000000..bc94114
--- /dev/null
+++ b/lib/route/qdisc/nssbf.c
@@ -0,0 +1,411 @@
+/*
+ * lib/route/qdisc/nssbf.c NSSBF 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
+ * @ingroup class
+ * @defgroup qdisc_nssbf BF Scheduler (NSSBF)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/nssbf.h>
+
+/** @cond SKIP */
+#define NSSBF_QDISC_ATTR_DEFCLS 0x001
+#define NSSBF_CLASS_ATTR_RATE 0x002
+#define NSSBF_CLASS_ATTR_BURST 0x004
+#define NSSBF_CLASS_ATTR_MTU 0x008
+#define NSSBF_CLASS_ATTR_QUANTUM 0x010
+/** @endcond */
+
+static struct nla_policy nssbf_policy[TCA_NSSBF_MAX+1] = {
+ [TCA_NSSBF_QDISC_PARMS] = { .minlen = sizeof(struct tc_nssbf_qopt) },
+ [TCA_NSSBF_CLASS_PARMS] = { .minlen = sizeof(struct tc_nssbf_class_qopt) },
+};
+
+static struct nla_policy nssbf_class_policy[TCA_NSSBF_MAX+1] = {
+};
+
+static int nssbf_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct nlattr *tb[TCA_NSSBF_MAX + 1];
+ struct rtnl_nssbf_qdisc *nssbf = data;
+ struct tc_nssbf_qopt *opts;
+ int err;
+
+ if ((err = tca_parse(tb, TCA_NSSBF_MAX, tc, nssbf_policy)) < 0)
+ return err;
+
+ if (tb[TCA_NSSBF_QDISC_PARMS]) {
+ opts = nla_data(tb[TCA_NSSBF_QDISC_PARMS]);
+
+ nssbf->awv_mask = 0;
+
+ nssbf->awv_defcls = opts->defcls;
+ nssbf->awv_mask |= NSSBF_QDISC_ATTR_DEFCLS;
+ }
+
+ return 0;
+}
+
+static int nssbf_class_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct nlattr *tb[TCA_NSSBF_MAX + 1];
+ struct rtnl_nssbf_class *nssbf = data;
+ struct tc_nssbf_class_qopt *opts;
+ int err;
+
+ if ((err = tca_parse(tb, TCA_NSSBF_MAX, tc, nssbf_policy)) < 0)
+ return err;
+
+ if (tb[TCA_NSSBF_CLASS_PARMS]) {
+ opts = nla_data(tb[TCA_NSSBF_CLASS_PARMS]);
+
+ nssbf->ery_mask = 0;
+
+ nssbf->ery_rate = opts->rate;
+ nssbf->ery_mask |= NSSBF_CLASS_ATTR_RATE;
+
+ nssbf->ery_burst = opts->burst;
+ nssbf->ery_mask |= NSSBF_CLASS_ATTR_BURST;
+
+ nssbf->ery_mtu = opts->mtu;
+ nssbf->ery_mask |= NSSBF_CLASS_ATTR_MTU;
+
+ nssbf->ery_quantum = opts->quantum;
+ nssbf->ery_mask |= NSSBF_CLASS_ATTR_QUANTUM;
+ }
+
+ return 0;
+}
+
+static void nssbf_qdisc_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_nssbf_qdisc *nssbf = data;
+
+ if (!nssbf)
+ return;
+
+ if (nssbf->awv_mask & NSSBF_QDISC_ATTR_DEFCLS) {
+ char buf[64];
+ nl_dump(p, " default-class %s",
+ rtnl_tc_handle2str(nssbf->awv_defcls,
+ buf, sizeof(buf)));
+ }
+}
+
+static void nssbf_class_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_nssbf_class *nssbf = data;
+
+ if (!nssbf)
+ return;
+
+ if (nssbf->ery_mask & NSSBF_CLASS_ATTR_RATE) {
+ nl_dump(p, " Rate %u", nssbf->ery_rate);
+ }
+}
+
+static int nssbf_qdisc_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_nssbf_qdisc *nssbf = data;
+ struct tc_nssbf_qopt opts;
+
+ memset(&opts, 0, sizeof(opts));
+
+ if (nssbf) {
+ if (nssbf->awv_mask & NSSBF_QDISC_ATTR_DEFCLS)
+ opts.defcls = nssbf->awv_defcls;
+ }
+
+ NLA_PUT(msg, TCA_NSSBF_QDISC_PARMS, sizeof(opts), &opts);
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+static int nssbf_class_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_nssbf_class *nssbf = data;
+ struct tc_nssbf_class_qopt opts;
+ uint32_t required = NSSBF_CLASS_ATTR_RATE | NSSBF_CLASS_ATTR_BURST;
+
+ if (!nssbf)
+ return 0;
+
+ if ((nssbf->ery_mask & required) != required)
+ return -NLE_MISSING_ATTR;
+
+ memset(&opts, 0, sizeof(opts));
+
+ opts.rate = nssbf->ery_rate;
+ opts.burst = nssbf->ery_burst;
+
+ if (nssbf->ery_mask & NSSBF_CLASS_ATTR_MTU) {
+ opts.mtu = nssbf->ery_mtu;
+ }
+
+ if (nssbf->ery_mask & NSSBF_CLASS_ATTR_QUANTUM) {
+ opts.quantum = nssbf->ery_quantum;
+ }
+
+ NLA_PUT(msg, TCA_NSSBF_CLASS_PARMS, sizeof(opts), &opts);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set defcls of NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc to be modified
+ * @arg defcls New defcls for the qdisc
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nssbf_qdisc_set_defcls(struct rtnl_qdisc *qdisc, uint16_t defcls)
+{
+ struct rtnl_nssbf_qdisc *nssbf_qdisc;
+
+ if (!(nssbf_qdisc = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nssbf_qdisc->awv_defcls = defcls;
+ nssbf_qdisc->awv_mask |= NSSBF_QDISC_ATTR_DEFCLS;
+ return 0;
+}
+
+/**
+ * Get defcls of a NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc.
+ * @return defcls value.
+ */
+uint32_t rtnl_nssbf_qdisc_get_defcls(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nssbf_qdisc *nssbf_qdisc;
+
+ if ((nssbf_qdisc = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nssbf_qdisc->awv_mask & NSSBF_QDISC_ATTR_DEFCLS)) {
+
+ return nssbf_qdisc->awv_defcls;
+ }
+
+ return TC_H_UNSPEC;
+}
+
+/**
+ * Set rate of NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc to be modified
+ * @arg rate New rate in bytes per second
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nssbf_class_set_rate(struct rtnl_class *class, uint32_t rate)
+{
+ struct rtnl_nssbf_class *nssbf_class;
+
+ if (!(nssbf_class = rtnl_tc_data(TC_CAST(class))))
+ return -NLE_NOMEM;
+
+ nssbf_class->ery_rate = rate;
+ nssbf_class->ery_mask |= NSSBF_CLASS_ATTR_RATE;
+ return 0;
+}
+
+/**
+ * Get rate of a NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc.
+ * @return configured rate in bytes per second.
+ */
+uint32_t rtnl_nssbf_class_get_rate(struct rtnl_class *class)
+{
+ struct rtnl_nssbf_class *nssbf_class;
+
+ if ((nssbf_class = rtnl_tc_data(TC_CAST(class))) &&
+ (nssbf_class->ery_mask & NSSBF_CLASS_ATTR_RATE)) {
+
+ return nssbf_class->ery_rate;
+ }
+
+ return 0;
+}
+
+/**
+ * Set burst of NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc to be modified
+ * @arg burst New burst size in bytes.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nssbf_class_set_burst(struct rtnl_class *class, uint32_t burst)
+{
+ struct rtnl_nssbf_class *nssbf_class;
+
+ if (!(nssbf_class = rtnl_tc_data(TC_CAST(class))))
+ return -NLE_NOMEM;
+
+ nssbf_class->ery_burst = burst;
+ nssbf_class->ery_mask |= NSSBF_CLASS_ATTR_BURST;
+ return 0;
+}
+
+/**
+ * Get burst of a NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc.
+ * @return configured burst in bytes.
+ */
+uint32_t rtnl_nssbf_class_get_burst(struct rtnl_class *class)
+{
+ struct rtnl_nssbf_class *nssbf_class;
+
+ if ((nssbf_class = rtnl_tc_data(TC_CAST(class))) &&
+ (nssbf_class->ery_mask & NSSBF_CLASS_ATTR_BURST)) {
+
+ return nssbf_class->ery_burst;
+ }
+
+ return 0;
+}
+
+/**
+ * Set mtu of NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc to be modified
+ * @arg mtu New mtu in bytes
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nssbf_class_set_mtu(struct rtnl_class *class, uint32_t mtu)
+{
+ struct rtnl_nssbf_class *nssbf_class;
+
+ if (!(nssbf_class = rtnl_tc_data(TC_CAST(class))))
+ return -NLE_NOMEM;
+
+ nssbf_class->ery_mtu = mtu;
+ nssbf_class->ery_mask |= NSSBF_CLASS_ATTR_MTU;
+ return 0;
+}
+
+/**
+ * Get mtu of a NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc.
+ * @return configured mtu in bytes.
+ */
+uint32_t rtnl_nssbf_class_get_mtu(struct rtnl_class *class)
+{
+ struct rtnl_nssbf_class *nssbf_class;
+
+ if ((nssbf_class = rtnl_tc_data(TC_CAST(class))) &&
+ (nssbf_class->ery_mask & NSSBF_CLASS_ATTR_MTU)) {
+
+ return nssbf_class->ery_mtu;
+ }
+
+ return 0;
+}
+
+/**
+ * Set quantum of NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc to be modified
+ * @arg quantum New quantum
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nssbf_class_set_quantum(struct rtnl_class *class, uint32_t quantum)
+{
+ struct rtnl_nssbf_class *nssbf_class;
+
+ if (!(nssbf_class = rtnl_tc_data(TC_CAST(class))))
+ return -NLE_NOMEM;
+
+ nssbf_class->ery_quantum = quantum;
+ nssbf_class->ery_mask |= NSSBF_CLASS_ATTR_QUANTUM;
+ return 0;
+}
+
+/**
+ * Get quantum of a NSSBF qdisc.
+ * @arg qdisc NSSBF qdisc.
+ * @return configured quantum
+ */
+uint32_t rtnl_nssbf_class_get_quantum(struct rtnl_class *class)
+{
+ struct rtnl_nssbf_class *nssbf_class;
+
+ if ((nssbf_class = rtnl_tc_data(TC_CAST(class))) &&
+ (nssbf_class->ery_mask & NSSBF_CLASS_ATTR_QUANTUM)) {
+
+ return nssbf_class->ery_quantum;
+ }
+
+ return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops nssbf_qdisc_ops = {
+ .to_kind = "nssbf",
+ .to_type = RTNL_TC_TYPE_QDISC,
+ .to_size = sizeof(struct rtnl_nssbf_qdisc),
+ .to_msg_parser = nssbf_qdisc_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = nssbf_qdisc_dump_line,
+ [NL_DUMP_DETAILS] = NULL,
+ },
+ .to_msg_fill = nssbf_qdisc_msg_fill,
+};
+
+static struct rtnl_tc_ops nssbf_class_ops = {
+ .to_kind = "nssbf",
+ .to_type = RTNL_TC_TYPE_CLASS,
+ .to_size = sizeof(struct rtnl_nssbf_class),
+ .to_msg_parser = nssbf_class_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = nssbf_class_dump_line,
+ [NL_DUMP_DETAILS] = NULL,
+ },
+ .to_msg_fill = nssbf_class_msg_fill,
+};
+
+static void __init nssbf_init(void)
+{
+ rtnl_tc_register(&nssbf_qdisc_ops);
+ rtnl_tc_register(&nssbf_class_ops);
+}
+
+static void __exit nssbf_exit(void)
+{
+ rtnl_tc_unregister(&nssbf_class_ops);
+ rtnl_tc_unregister(&nssbf_qdisc_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/nsscodel.c b/lib/route/qdisc/nsscodel.c
new file mode 100644
index 0000000..c8b5fa9
--- /dev/null
+++ b/lib/route/qdisc/nsscodel.c
@@ -0,0 +1,312 @@
+/*
+ * lib/route/qdisc/nsscodel.c NSSCODEL 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_nsscodel CODEL Queue (NSSCODEL)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/nsscodel.h>
+
+/** @cond SKIP */
+#define NSSCODEL_ATTR_TARGET 0x01
+#define NSSCODEL_ATTR_LIMIT 0x02
+#define NSSCODEL_ATTR_INTERVAL 0x04
+#define NSSCODEL_ATTR_SET_DEFAULT 0x08
+/** @endcond */
+
+static struct nla_policy nsscodel_policy[TCA_NSSCODEL_MAX + 1] = {
+ [TCA_NSSCODEL_PARMS] = { .minlen = sizeof(struct tc_nsscodel_qopt) },
+};
+
+static int nsscodel_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_nsscodel *nsscodel = data;
+ struct nlattr *tb[TCA_NSSCODEL_MAX + 1];
+ struct tc_nsscodel_qopt *opts;
+ int err;
+
+ err = tca_parse(tb, TCA_NSSCODEL_MAX, tc, nsscodel_policy);
+ if (err < 0)
+ return err;
+
+
+ if (!tb[TCA_NSSCODEL_PARMS])
+ return -NLE_MISSING_ATTR;
+
+ opts = nla_data(tb[TCA_NSSCODEL_PARMS]);
+
+ nsscodel->anf_mask = 0;
+
+ nsscodel->anf_target = opts->target;
+ nsscodel->anf_mask |= NSSCODEL_ATTR_TARGET;
+
+ nsscodel->anf_limit = opts->limit;
+ nsscodel->anf_mask |= NSSCODEL_ATTR_LIMIT;
+
+ nsscodel->anf_interval = opts->interval;
+ nsscodel->anf_mask |= NSSCODEL_ATTR_INTERVAL;
+
+ nsscodel->anf_set_default = opts->set_default;
+ nsscodel->anf_mask |= NSSCODEL_ATTR_SET_DEFAULT;
+
+ return 0;
+}
+
+static void nsscodel_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_nsscodel *nsscodel = data;
+
+ if (nsscodel && (nsscodel->anf_mask & NSSCODEL_ATTR_TARGET))
+ nl_dump(p, " target %u ms", nsscodel->anf_target);
+}
+
+static void nsscodel_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_nsscodel *nsscodel = data;
+
+ if (!nsscodel)
+ return;
+
+ if (nsscodel->anf_mask & NSSCODEL_ATTR_LIMIT)
+ nl_dump(p, " limit %u packets", nsscodel->anf_limit);
+
+ if (nsscodel->anf_mask & NSSCODEL_ATTR_INTERVAL)
+ nl_dump(p, " interval %u ms", nsscodel->anf_interval);
+
+ if (nsscodel->anf_mask & NSSCODEL_ATTR_SET_DEFAULT)
+ nl_dump(p, " set_default %u", nsscodel->anf_set_default);
+}
+
+static int nsscodel_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct tc_nsscodel_qopt opts;
+ struct rtnl_nsscodel *nsscodel = data;
+ uint32_t required = NSSCODEL_ATTR_TARGET | NSSCODEL_ATTR_INTERVAL;
+
+ if (!nsscodel )
+ return 0;
+
+ if ((nsscodel->anf_mask & required) != required)
+ return -NLE_MISSING_ATTR;
+
+ memset(&opts, 0, sizeof(opts));
+
+ opts.target = nsscodel->anf_target;
+ opts.interval = nsscodel->anf_interval;
+
+ if (nsscodel->anf_mask & NSSCODEL_ATTR_LIMIT)
+ opts.limit = nsscodel->anf_limit;
+
+ if (nsscodel->anf_mask & NSSCODEL_ATTR_SET_DEFAULT)
+ opts.set_default = nsscodel->anf_set_default;
+
+ NLA_PUT(msg, TCA_NSSCODEL_PARMS, sizeof(opts), &opts);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set limit of NSSCODEL qdisc.
+ * @arg qdisc NSSCODEL qdisc to be modified
+ * @arg limit Queue limit in packets
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nsscodel_set_limit(struct rtnl_qdisc *qdisc, uint32_t limit)
+{
+ struct rtnl_nsscodel *nsscodel;
+
+ if (!(nsscodel = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nsscodel->anf_limit = limit;
+ nsscodel->anf_mask |= NSSCODEL_ATTR_LIMIT;
+ return 0;
+}
+
+/**
+ * Get limit of a NSSCODEL qdisc.
+ * @arg qdisc NSSCODEL qdisc.
+ * @return limit value in number of packets.
+ */
+uint32_t rtnl_nsscodel_get_limit(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nsscodel *nsscodel;
+
+ if ((nsscodel = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nsscodel->anf_mask & NSSCODEL_ATTR_LIMIT)) {
+
+ return nsscodel->anf_limit;
+ }
+
+ return 0;
+}
+
+/**
+ * Set target of NSSCODEL qdisc.
+ * @arg qdisc NSSCODEL qdisc to be modified
+ * @arg target New target delay in usec.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nsscodel_set_target(struct rtnl_qdisc *qdisc, uint32_t target)
+{
+ struct rtnl_nsscodel *nsscodel;
+
+ if (!(nsscodel = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nsscodel->anf_target = target;
+ nsscodel->anf_mask |= NSSCODEL_ATTR_TARGET;
+ return 0;
+}
+
+/**
+ * Get target of a NSSCODEL qdisc.
+ * @arg qdisc NSSCODEL qdisc.
+ * @return target value in usec.
+ */
+uint32_t rtnl_nsscodel_get_target(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nsscodel *nsscodel;
+
+ if ((nsscodel = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nsscodel->anf_mask & NSSCODEL_ATTR_TARGET)) {
+
+ return nsscodel->anf_target;
+ }
+
+ return 0;
+}
+
+/**
+ * Set interval of NSSCODEL qdisc.
+ * @arg qdisc NSSCODEL qdisc to be modified
+ * @arg interval New interval for the qdisc in usec.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nsscodel_set_interval(struct rtnl_qdisc *qdisc, uint32_t interval)
+{
+ struct rtnl_nsscodel *nsscodel;
+
+ if (!(nsscodel = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nsscodel->anf_interval = interval;
+ nsscodel->anf_mask |= NSSCODEL_ATTR_INTERVAL;
+ return 0;
+}
+
+/**
+ * Get interval of a NSSCODEL qdisc.
+ * @arg qdisc NSSCODEL qdisc.
+ * @return interval in usec.
+ */
+uint32_t rtnl_nsscodel_get_interval(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nsscodel *nsscodel;
+
+ if ((nsscodel = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nsscodel->anf_mask & NSSCODEL_ATTR_INTERVAL)) {
+
+ return nsscodel->anf_interval;
+ }
+
+ return 0;
+}
+
+/**
+ * Set set_default of NSSCODEL qdisc.
+ * @arg qdisc NSSCODEL qdisc to be modified
+ * @arg set_default A value > 0 will make this the default enqueue node.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nsscodel_set_default(struct rtnl_qdisc *qdisc, uint8_t set_default)
+{
+ struct rtnl_nsscodel *nsscodel;
+
+ if (!(nsscodel = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nsscodel->anf_set_default = set_default;
+ nsscodel->anf_mask |= NSSCODEL_ATTR_SET_DEFAULT;
+ return 0;
+}
+
+/**
+ * Get set_default of a NSSCODEL qdisc.
+ * @arg qdisc NSSCODEL qdisc.
+ * @return set_default value. Value > 0 means this is the default enqueue node.
+ */
+uint8_t rtnl_nsscodel_get_default(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nsscodel *nsscodel;
+
+ if ((nsscodel = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nsscodel->anf_mask & NSSCODEL_ATTR_SET_DEFAULT)) {
+
+ return nsscodel->anf_set_default;
+ }
+
+ return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops nsscodel_qdisc_ops = {
+ .to_kind = "nsscodel",
+ .to_type = RTNL_TC_TYPE_QDISC,
+ .to_size = sizeof(struct rtnl_nsscodel),
+ .to_msg_parser = nsscodel_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = nsscodel_dump_line,
+ [NL_DUMP_DETAILS] = nsscodel_dump_details,
+ },
+ .to_msg_fill = nsscodel_msg_fill,
+};
+
+static void __init nsscodel_init(void)
+{
+ rtnl_tc_register(&nsscodel_qdisc_ops);
+}
+
+static void __exit nsscodel_exit(void)
+{
+ rtnl_tc_unregister(&nsscodel_qdisc_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/nssfifo.c b/lib/route/qdisc/nssfifo.c
new file mode 100644
index 0000000..fc95b10
--- /dev/null
+++ b/lib/route/qdisc/nssfifo.c
@@ -0,0 +1,216 @@
+/*
+ * lib/route/qdisc/nssfifo.c
+ */
+/*
+ **************************************************************************
+ * 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_nssfifo FIFO Queue (NSSFIFO)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/nssfifo.h>
+#include <netlink/utils.h>
+
+/** @cond */
+#define NSSFIFO_ATTR_LIMIT 0x01
+#define NSSFIFO_ATTR_SET_DEFAULT 0x02
+/** @endcond */
+
+static struct nla_policy nssfifo_policy[TCA_NSSFIFO_MAX + 1] = {
+ [TCA_NSSFIFO_PARMS] = { .minlen = sizeof(struct tc_nssfifo_qopt) },
+};
+
+static int nssfifo_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct nlattr *tb[TCA_NSSFIFO_MAX + 1];
+ struct rtnl_nssfifo *nssfifo = data;
+ struct tc_nssfifo_qopt *opts;
+ int err;
+
+ err = tca_parse(tb, TCA_NSSFIFO_MAX, tc, nssfifo_policy);
+ if (err < 0)
+ return err;
+
+ if (!tb[TCA_NSSFIFO_PARMS])
+ return -NLE_MISSING_ATTR;
+
+ opts = nla_data(tb[TCA_NSSFIFO_PARMS]);
+
+ nssfifo->qpf_mask = 0;
+
+ nssfifo->qpf_limit = opts->limit;
+ nssfifo->qpf_mask |= NSSFIFO_ATTR_LIMIT;
+
+ nssfifo->qpf_set_default = opts->set_default;
+ nssfifo->qpf_mask |= NSSFIFO_ATTR_SET_DEFAULT;
+
+ return 0;
+}
+
+static void nssfifo_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_nssfifo *nssfifo = data;
+
+ if (nssfifo && (nssfifo->qpf_mask & NSSFIFO_ATTR_LIMIT))
+ nl_dump(p, " limit %u packets", nssfifo->qpf_limit);
+}
+
+static void nssfifo_dump_details(struct rtnl_tc *tc, void *data, struct nl_dump_params *p)
+{
+ struct rtnl_nssfifo *nssfifo = data;
+
+ if (!nssfifo)
+ return;
+
+ if (nssfifo && (nssfifo->qpf_mask & NSSFIFO_ATTR_SET_DEFAULT))
+ nl_dump(p, " set_default %u", nssfifo->qpf_set_default);
+}
+
+static int nssfifo_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_nssfifo *nssfifo = data;
+ struct tc_nssfifo_qopt opts;
+
+ if (!nssfifo)
+ return -NLE_INVAL;
+
+ memset(&opts, 0, sizeof(opts));
+
+ if (nssfifo->qpf_mask & NSSFIFO_ATTR_LIMIT)
+ opts.limit = nssfifo->qpf_limit;
+
+ if (nssfifo->qpf_mask & NSSFIFO_ATTR_SET_DEFAULT)
+ opts.set_default = nssfifo->qpf_set_default;
+
+ NLA_PUT(msg, TCA_NSSFIFO_PARMS, sizeof(opts), &opts);
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+/**
+ * Set limit of NSSFIFO qdisc.
+ * @arg qdisc NSSFIFO qdisc to be modified.
+ * @arg limit New limit in number of packets.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nssfifo_set_limit(struct rtnl_qdisc *qdisc, uint32_t limit)
+{
+ struct rtnl_nssfifo *nssfifo;
+
+ if (!(nssfifo = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nssfifo->qpf_limit = limit;
+ nssfifo->qpf_mask |= NSSFIFO_ATTR_LIMIT;
+
+ return 0;
+}
+
+/**
+ * Get limit of a NSSFIFO qdisc.
+ * @arg qdisc NSSFIFO qdisc.
+ * @return limit in number of packets.
+ */
+uint32_t rtnl_nssfifo_get_limit(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nssfifo *nssfifo;
+
+ if ((nssfifo = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nssfifo->qpf_mask & NSSFIFO_ATTR_LIMIT)) {
+
+ return nssfifo->qpf_limit;
+ }
+
+ return 0;
+}
+
+/**
+ * Set set_default of NSSFIFO qdisc.
+ * @arg qdisc NSSFIFO qdisc to be modified.
+ * @arg set_default If this qdisc needs to be the default enqueue node.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nssfifo_set_default(struct rtnl_qdisc *qdisc, uint8_t set_default)
+{
+ struct rtnl_nssfifo *nssfifo;
+
+ if (!(nssfifo = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nssfifo->qpf_set_default = set_default;
+ nssfifo->qpf_mask |= NSSFIFO_ATTR_SET_DEFAULT;
+
+ return 0;
+}
+
+/**
+ * Get limit of a NSSFIFO qdisc.
+ * @arg qdisc NSSFIFO qdisc.
+ * @return set_default flag
+ */
+uint8_t rtnl_nssfifo_get_default(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nssfifo *nssfifo;
+
+ if ((nssfifo = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nssfifo->qpf_mask & NSSFIFO_ATTR_SET_DEFAULT)) {
+
+ return nssfifo->qpf_set_default;
+ }
+
+ return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops nsspfifo_ops = {
+ .to_kind = "nsspfifo",
+ .to_type = RTNL_TC_TYPE_QDISC,
+ .to_size = sizeof(struct rtnl_nssfifo),
+ .to_msg_parser = nssfifo_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = nssfifo_dump_line,
+ [NL_DUMP_DETAILS] = nssfifo_dump_details,
+ },
+ .to_msg_fill = nssfifo_msg_fill,
+};
+
+static void __init nssfifo_init(void)
+{
+ rtnl_tc_register(&nsspfifo_ops);
+}
+
+static void __exit nssfifo_exit(void)
+{
+ rtnl_tc_unregister(&nsspfifo_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/nssprio.c b/lib/route/qdisc/nssprio.c
new file mode 100644
index 0000000..77e6363
--- /dev/null
+++ b/lib/route/qdisc/nssprio.c
@@ -0,0 +1,162 @@
+/*
+ * lib/route/qdisc/nssprio.c NSSPRIO Qdisc/Class
+ */
+/*
+ **************************************************************************
+ * 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
+ * @ingroup class
+ * @defgroup qdisc_nssprio PRIO Qdisc/Class (NSSPRIO)
+ * @{
+ */
+
+#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/nssprio.h>
+
+/** @cond SKIP */
+#define NSSPRIO_ATTR_BANDS 0x01
+/** @endcond */
+
+static struct nla_policy nssprio_policy[TCA_NSSPRIO_MAX + 1] = {
+ [TCA_NSSPRIO_PARMS] = { .minlen = sizeof(struct tc_nssprio_qopt) },
+};
+
+static int nssprio_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct nlattr *tb[TCA_NSSPRIO_MAX + 1];
+ struct rtnl_nssprio *nssprio = data;
+ struct tc_nssprio_qopt *opt;
+ int err;
+
+ err = tca_parse(tb, TCA_NSSPRIO_MAX, tc, nssprio_policy);
+ if (err < 0)
+ return err;
+
+ if (!tb[TCA_NSSPRIO_PARMS])
+ return -NLE_MISSING_ATTR;
+
+ opt = nla_data(tb[TCA_NSSPRIO_PARMS]);
+
+ nssprio->agj_mask = 0;
+
+ nssprio->agj_bands = opt->bands;
+ nssprio->agj_mask |= NSSPRIO_ATTR_BANDS;
+
+ return 0;
+}
+
+static void nssprio_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_nssprio *nssprio = data;
+
+ if (nssprio && (nssprio->agj_mask & NSSPRIO_ATTR_BANDS))
+ nl_dump(p, " bands %u", nssprio->agj_bands);
+}
+
+static int nssprio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_nssprio *nssprio = data;
+ struct tc_nssprio_qopt opt;
+
+ if (!nssprio)
+ return -NLE_INVAL;
+
+ memset(&opt, 0, sizeof(opt));
+
+ if (nssprio->agj_mask & NSSPRIO_ATTR_BANDS)
+ opt.bands = nssprio->agj_bands;
+
+ NLA_PUT(msg, TCA_NSSPRIO_PARMS, sizeof(opt), &opt);
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+/**
+ * Set bands for NSSPRIO qdisc.
+ * @arg qdisc NSSPRIO qdisc to be modified.
+ * @arg bands Number of bands for nssprio.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nssprio_set_bands(struct rtnl_qdisc *qdisc, int bands)
+{
+ struct rtnl_nssprio *nssprio;
+
+ if (!(nssprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nssprio->agj_bands = bands;
+ nssprio->agj_mask |= NSSPRIO_ATTR_BANDS;
+
+ return 0;
+}
+
+/**
+ * Get bands of a NSSPRIO qdisc.
+ * @arg qdisc NSSPRIO qdisc.
+ * @return number of bands used.
+ */
+int rtnl_nssprio_get_bands(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nssprio *nssprio;
+
+ if ((nssprio = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nssprio->agj_mask & NSSPRIO_ATTR_BANDS)) {
+
+ return nssprio->agj_bands;
+ }
+
+ return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops nssprio_ops = {
+ .to_kind = "nssprio",
+ .to_type = RTNL_TC_TYPE_QDISC,
+ .to_size = sizeof(struct rtnl_nssprio),
+ .to_msg_parser = nssprio_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = nssprio_dump_line,
+ [NL_DUMP_DETAILS] = NULL,
+ },
+ .to_msg_fill = nssprio_msg_fill,
+};
+
+static void __init nssprio_init(void)
+{
+ rtnl_tc_register(&nssprio_ops);
+}
+
+static void __exit nssprio_exit(void)
+{
+ rtnl_tc_unregister(&nssprio_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/nsstbl.c b/lib/route/qdisc/nsstbl.c
new file mode 100644
index 0000000..637917d
--- /dev/null
+++ b/lib/route/qdisc/nsstbl.c
@@ -0,0 +1,331 @@
+/*
+ * lib/route/qdisc/nsstbl.c NSSTBL 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_nsstbl NSS Token Bucket Limiter (NSSTBL)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/nsstbl.h>
+
+/** @cond SKIP */
+#define NSSTBL_ATTR_RATE 0x01
+#define NSSTBL_ATTR_BURST 0x02
+#define NSSTBL_ATTR_PEAKRATE 0x04
+#define NSSTBL_ATTR_MTU 0x08
+/** @endcond */
+
+static struct nla_policy nsstbl_policy[TCA_NSSTBL_MAX+1] = {
+ [TCA_NSSTBL_PARMS] = { .minlen = sizeof(struct tc_nsstbl_qopt) },
+};
+
+static int nsstbl_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct nlattr *tb[TCA_NSSTBL_MAX + 1];
+ struct rtnl_nsstbl *nsstbl = data;
+ struct tc_nsstbl_qopt *opts;
+ int err;
+
+ if ((err = tca_parse(tb, TCA_NSSTBL_MAX, tc, nsstbl_policy)) < 0)
+ return err;
+
+ if (!tb[TCA_NSSTBL_PARMS])
+ return -NLE_MISSING_ATTR;
+
+ opts = nla_data(tb[TCA_NSSTBL_PARMS]);
+
+ nsstbl->ias_mask = 0;
+
+ nsstbl->ias_rate = opts->rate;
+ nsstbl->ias_mask |= NSSTBL_ATTR_RATE;
+
+ nsstbl->ias_burst = opts->burst;
+ nsstbl->ias_mask |= NSSTBL_ATTR_BURST;
+
+ nsstbl->ias_peakrate = opts->peakrate;
+ nsstbl->ias_mask |= NSSTBL_ATTR_PEAKRATE;
+
+ nsstbl->ias_mtu = opts->mtu;
+ nsstbl->ias_mask |= NSSTBL_ATTR_MTU;
+
+ return 0;
+}
+
+static void nsstbl_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ double r, rbit;
+ char *ru, *rubit;
+ struct rtnl_nsstbl *nsstbl = data;
+
+ if (!nsstbl)
+ return;
+
+ r = nl_cancel_down_bytes(nsstbl->ias_rate, &ru);
+ rbit = nl_cancel_down_bits(nsstbl->ias_rate*8, &rubit);
+
+ nl_dump(p, " rate %.2f%s/s (%.0f%s)",
+ r, ru, rbit, rubit);
+}
+
+static void nsstbl_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_nsstbl *nsstbl = data;
+
+ if (!nsstbl)
+ return;
+
+ if (1) {
+ char *bu;
+ double bs = nl_cancel_down_bytes(nsstbl->ias_burst, &bu);
+
+ nl_dump(p, "rate-bucket-size %1.f%s ",
+ bs, bu);
+
+ }
+
+ if (nsstbl->ias_mask & NSSTBL_ATTR_PEAKRATE) {
+ char *pru, *prbu, *bsu;
+ double pr, prb, bs;
+
+ pr = nl_cancel_down_bytes(nsstbl->ias_peakrate, &pru);
+ prb = nl_cancel_down_bits(nsstbl->ias_peakrate*8, &prbu);
+ bs = nl_cancel_down_bits(nsstbl->ias_mtu, &bsu);
+
+ nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) "
+ "bucket-size %.1f%s",
+ pr, pru, prb, prbu, bs, bsu);
+ }
+}
+
+static int nsstbl_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct tc_nsstbl_qopt opts;
+ struct rtnl_nsstbl *nsstbl = data;
+ int required = NSSTBL_ATTR_RATE | NSSTBL_ATTR_BURST;
+
+ if ((nsstbl->ias_mask & required) != required)
+ return -NLE_MISSING_ATTR;
+
+ memset(&opts, 0, sizeof(opts));
+
+ opts.rate = nsstbl->ias_rate;
+ opts.burst = nsstbl->ias_burst;
+
+ if (nsstbl->ias_mask & NSSTBL_ATTR_MTU) {
+ opts.mtu = nsstbl->ias_mtu;
+ }
+
+ if (nsstbl->ias_mask & NSSTBL_ATTR_PEAKRATE) {
+ opts.peakrate = nsstbl->ias_peakrate;
+ }
+
+ NLA_PUT(msg, TCA_NSSTBL_PARMS, sizeof(opts), &opts);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set rate of NSSTBL qdisc.
+ * @arg qdisc NSSTBL qdisc to be modified
+ * @arg rate New rate in bytes per second
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nsstbl_set_rate(struct rtnl_qdisc *qdisc, uint32_t rate)
+{
+ struct rtnl_nsstbl *nsstbl;
+
+ if (!(nsstbl = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nsstbl->ias_rate = rate;
+ nsstbl->ias_mask |= NSSTBL_ATTR_RATE;
+ return 0;
+}
+
+/**
+ * Get rate of a NSSTBL qdisc.
+ * @arg qdisc NSSTBL qdisc.
+ * @return configured rate in bytes per second.
+ */
+uint32_t rtnl_nsstbl_get_rate(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nsstbl *nsstbl;
+
+ if ((nsstbl = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nsstbl->ias_mask & NSSTBL_ATTR_RATE)) {
+
+ return nsstbl->ias_rate;
+ }
+
+ return 0;
+}
+
+/**
+ * Set burst of NSSTBL qdisc.
+ * @arg qdisc NSSTBL qdisc to be modified
+ * @arg burst New burst size in bytes.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nsstbl_set_burst(struct rtnl_qdisc *qdisc, uint32_t burst)
+{
+ struct rtnl_nsstbl *nsstbl;
+
+ if (!(nsstbl = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nsstbl->ias_burst = burst;
+ nsstbl->ias_mask |= NSSTBL_ATTR_BURST;
+ return 0;
+}
+
+/**
+ * Get burst of a NSSTBL qdisc.
+ * @arg qdisc NSSTBL qdisc.
+ * @return configured burst in bytes.
+ */
+uint32_t rtnl_nsstbl_get_burst(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nsstbl *nsstbl;
+
+ if ((nsstbl = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nsstbl->ias_mask & NSSTBL_ATTR_BURST)) {
+
+ return nsstbl->ias_burst;
+ }
+
+ return 0;
+}
+
+/**
+ * Set mtu of NSSTBL qdisc.
+ * @arg qdisc NSSTBL qdisc to be modified
+ * @arg mtu New mtu in bytes
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nsstbl_set_mtu(struct rtnl_qdisc *qdisc, uint32_t mtu)
+{
+ struct rtnl_nsstbl *nsstbl;
+
+ if (!(nsstbl = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nsstbl->ias_mtu = mtu;
+ nsstbl->ias_mask |= NSSTBL_ATTR_MTU;
+ return 0;
+}
+
+/**
+ * Get mtu of a NSSTBL qdisc.
+ * @arg qdisc NSSTBL qdisc.
+ * @return configured mtu in bytes.
+ */
+uint32_t rtnl_nsstbl_get_mtu(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nsstbl *nsstbl;
+
+ if ((nsstbl = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nsstbl->ias_mask & NSSTBL_ATTR_MTU)) {
+
+ return nsstbl->ias_mtu;
+ }
+
+ return 0;
+}
+
+/**
+ * Set peakrate of NSSTBL qdisc.
+ * @arg qdisc NSSTBL qdisc to be modified
+ * @arg peakrate New peakrate in bytes per second
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_nsstbl_set_peakrate(struct rtnl_qdisc *qdisc, uint32_t peakrate)
+{
+ struct rtnl_nsstbl *nsstbl;
+
+ if (!(nsstbl = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ nsstbl->ias_peakrate = peakrate;
+ nsstbl->ias_mask |= NSSTBL_ATTR_PEAKRATE;
+ return 0;
+}
+
+/**
+ * Get peakrate of a NSSTBL qdisc.
+ * @arg qdisc NSSTBL qdisc.
+ * @return configured peakrate in bytes per second.
+ */
+uint32_t rtnl_nsstbl_get_peakrate(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_nsstbl *nsstbl;
+
+ if ((nsstbl = rtnl_tc_data(TC_CAST(qdisc))) &&
+ (nsstbl->ias_mask & NSSTBL_ATTR_PEAKRATE)) {
+
+ return nsstbl->ias_peakrate;
+ }
+
+ return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops nsstbl_tc_ops = {
+ .to_kind = "nsstbl",
+ .to_type = RTNL_TC_TYPE_QDISC,
+ .to_size = sizeof(struct rtnl_nsstbl),
+ .to_msg_parser = nsstbl_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = nsstbl_dump_line,
+ [NL_DUMP_DETAILS] = nsstbl_dump_details,
+ },
+ .to_msg_fill = nsstbl_msg_fill,
+};
+
+static void __init nsstbl_init(void)
+{
+ rtnl_tc_register(&nsstbl_tc_ops);
+}
+
+static void __exit nsstbl_exit(void)
+{
+ rtnl_tc_unregister(&nsstbl_tc_ops);
+}
+
+/** @} */