diff --git a/include/Makefile.am b/include/Makefile.am index 7b8f0bd..cf8d548 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -64,6 +64,8 @@ nobase_libnlinclude_HEADERS = \ netlink/route/qdisc/nssfifo.h \ netlink/route/qdisc/nssprio.h \ netlink/route/qdisc/nsstbl.h \ + netlink/route/qdisc/nssblackhole.h \ + netlink/route/qdisc/nsshtb.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 4eb702a..9e352c3 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -1,3 +1,19 @@ +/* + ************************************************************************** + * Copyright (c) 2014, 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 __LINUX_PKT_SCHED_H #define __LINUX_PKT_SCHED_H @@ -847,4 +863,43 @@ struct tc_nssbf_qopt { __u16 defcls; /* Default class value */ }; +/* NSSBLACKHOLE section */ + +enum { + TCA_NSSBLACKHOLE_UNSPEC, + TCA_NSSBLACKHOLE_PARMS, + __TCA_NSSBLACKHOLE_MAX +}; + +#define TCA_NSSBLACKHOLE_MAX (__TCA_NSSBLACKHOLE_MAX - 1) + +struct tc_nssblackhole_qopt { + __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ +}; + +/* NSSHTB section */ + +enum { + TCA_NSSHTB_UNSPEC, + TCA_NSSHTB_CLASS_PARMS, + TCA_NSSHTB_QDISC_PARMS, + __TCA_NSSHTB_MAX +}; + +#define TCA_NSSHTB_MAX (__TCA_NSSHTB_MAX - 1) + +struct tc_nsshtb_class_qopt { + __u32 burst; /* Expected burst size */ + __u32 rate; /* Expected bandwidth for this class */ + __u32 cburst; /* Maximum burst size */ + __u32 crate; /* Max allowed bandwidth for this class */ + __u32 quantum; /* Quantum allocation value for DRR */ + __u32 priority; /* Priority value associated with this class */ + __u32 overhead; /* Overhead in bytes per packet */ +}; + +struct tc_nsshtb_qopt { + __u32 r2q; /* Rate to quantum ratio */ +}; + #endif diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h index 6b6f91b..a0fb9bb 100644 --- a/include/netlink-private/types.h +++ b/include/netlink-private/types.h @@ -700,6 +700,28 @@ struct rtnl_nssbf_qdisc { uint32_t awv_mask; }; +struct rtnl_nssblackhole +{ + uint32_t jsh_mask; + uint8_t jsh_set_default; +}; + +struct rtnl_nsshtb_class { + uint32_t sud_burst; + uint32_t sud_rate; + uint32_t sud_cburst; + uint32_t sud_crate; + uint32_t sud_quantum; + uint32_t sud_priority; + uint32_t sud_overhead; + uint32_t sud_mask; +}; + +struct rtnl_nsshtb_qdisc { + uint32_t wek_r2q; + uint32_t wek_mask; +}; + struct rtnl_netem_corr { uint32_t nmc_delay; diff --git a/include/netlink/route/qdisc/nssblackhole.h b/include/netlink/route/qdisc/nssblackhole.h new file mode 100644 index 0000000..586a8be --- /dev/null +++ b/include/netlink/route/qdisc/nssblackhole.h @@ -0,0 +1,34 @@ +/* + ************************************************************************** + * Copyright (c) 2014, 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_NSSBLACKHOLE_H_ +#define NETLINK_NSSBLACKHOLE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_nssblackhole_set_default(struct rtnl_qdisc *, uint8_t); +extern uint8_t rtnl_nssblackhole_get_default(struct rtnl_qdisc *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc/nsshtb.h b/include/netlink/route/qdisc/nsshtb.h new file mode 100644 index 0000000..2316696 --- /dev/null +++ b/include/netlink/route/qdisc/nsshtb.h @@ -0,0 +1,55 @@ +/* + ************************************************************************** + * Copyright (c) 2014, 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_NSSHTB_H_ +#define NETLINK_NSSHTB_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_nsshtb_qdisc_set_r2q(struct rtnl_qdisc *qdisc, uint16_t r2q); +extern uint32_t rtnl_nsshtb_qdisc_get_r2q(struct rtnl_qdisc *qdisc); + +extern int rtnl_nsshtb_class_set_rate(struct rtnl_class *class, uint32_t rate); +extern uint32_t rtnl_nsshtb_class_get_rate(struct rtnl_class *class); + +extern int rtnl_nsshtb_class_set_burst(struct rtnl_class *class, uint32_t burst); +extern uint32_t rtnl_nsshtb_class_get_burst(struct rtnl_class *class); + +extern int rtnl_nsshtb_class_set_crate(struct rtnl_class *class, uint32_t crate); +extern uint32_t rtnl_nsshtb_class_get_crate(struct rtnl_class *class); + +extern int rtnl_nsshtb_class_set_cburst(struct rtnl_class *class, uint32_t cburst); +extern uint32_t rtnl_nsshtb_class_get_cburst(struct rtnl_class *class); + +extern int rtnl_nsshtb_class_set_quantum(struct rtnl_class *class, uint32_t q); +extern uint32_t rtnl_nsshtb_class_get_quantum(struct rtnl_class *class); + +extern int rtnl_nsshtb_class_set_priority(struct rtnl_class *class, uint32_t priority); +extern uint32_t rtnl_nsshtb_class_get_priority(struct rtnl_class *class); + +extern int rtnl_nsshtb_class_set_overhead(struct rtnl_class *class, uint32_t overhead); +extern uint32_t rtnl_nsshtb_class_get_overhead(struct rtnl_class *class); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/Makefile.am b/lib/Makefile.am index 8891a0f..5771456 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -83,6 +83,7 @@ libnl_route_3_la_SOURCES = \ route/qdisc/bf.c \ route/qdisc/nssfifo.c route/qdisc/nsstbl.c route/qdisc/nssbf.c \ route/qdisc/nssprio.c route/qdisc/nsscodel.c \ + route/qdisc/nssblackhole.c route/qdisc/nsshtb.c \ \ fib_lookup/lookup.c fib_lookup/request.c \ \ diff --git a/lib/route/qdisc/nssblackhole.c b/lib/route/qdisc/nssblackhole.c new file mode 100644 index 0000000..9a69ee5 --- /dev/null +++ b/lib/route/qdisc/nssblackhole.c @@ -0,0 +1,169 @@ +/* + ************************************************************************** + * Copyright (c) 2014, 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_nssblackhole FIFO Queue (NSSBLACKHOLE) + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond */ +#define NSSBLACKHOLE_ATTR_SET_DEFAULT 0x01 +/** @endcond */ + +static struct nla_policy nssblackhole_policy[TCA_NSSBLACKHOLE_MAX + 1] = { + [TCA_NSSBLACKHOLE_PARMS] = { .minlen = sizeof(struct tc_nssblackhole_qopt) }, +}; + +static int nssblackhole_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_NSSBLACKHOLE_MAX + 1]; + struct rtnl_nssblackhole *nssblackhole = data; + struct tc_nssblackhole_qopt *opts; + int err; + + err = tca_parse(tb, TCA_NSSBLACKHOLE_MAX, tc, nssblackhole_policy); + if (err < 0) + return err; + + if (!tb[TCA_NSSBLACKHOLE_PARMS]) + return -NLE_MISSING_ATTR; + + opts = nla_data(tb[TCA_NSSBLACKHOLE_PARMS]); + + nssblackhole->jsh_mask = 0; + + nssblackhole->jsh_set_default = opts->set_default; + nssblackhole->jsh_mask |= NSSBLACKHOLE_ATTR_SET_DEFAULT; + + return 0; +} + +static void nssblackhole_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_nssblackhole *nssblackhole = data; + + if (nssblackhole && (nssblackhole->jsh_mask & NSSBLACKHOLE_ATTR_SET_DEFAULT)) + nl_dump(p, " set_default %u", nssblackhole->jsh_set_default); +} + +static void nssblackhole_dump_details(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) +{ + struct rtnl_nssblackhole *nssblackhole = data; + + if (!nssblackhole) + return; + + if (nssblackhole && (nssblackhole->jsh_mask & NSSBLACKHOLE_ATTR_SET_DEFAULT)) + nl_dump(p, " set_default %u", nssblackhole->jsh_set_default); +} + +static int nssblackhole_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_nssblackhole *nssblackhole = data; + struct tc_nssblackhole_qopt opts; + + if (!nssblackhole) + return -NLE_INVAL; + + memset(&opts, 0, sizeof(opts)); + + if (nssblackhole->jsh_mask & NSSBLACKHOLE_ATTR_SET_DEFAULT) + opts.set_default = nssblackhole->jsh_set_default; + + NLA_PUT(msg, TCA_NSSBLACKHOLE_PARMS, sizeof(opts), &opts); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Attribute Modification + * @{ + */ + +/** + * Set set_default of NSSBLACKHOLE qdisc. + * @arg qdisc NSSBLACKHOLE 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_nssblackhole_set_default(struct rtnl_qdisc *qdisc, uint8_t set_default) +{ + struct rtnl_nssblackhole *nssblackhole; + + if (!(nssblackhole = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + nssblackhole->jsh_set_default = set_default; + nssblackhole->jsh_mask |= NSSBLACKHOLE_ATTR_SET_DEFAULT; + + return 0; +} + +/** + * Get set_default of a NSSBLACKHOLE qdisc. + * @arg qdisc NSSBLACKHOLE qdisc. + * @return set_default flag + */ +uint8_t rtnl_nssblackhole_get_default(struct rtnl_qdisc *qdisc) +{ + struct rtnl_nssblackhole *nssblackhole; + + if ((nssblackhole = rtnl_tc_data(TC_CAST(qdisc))) && + (nssblackhole->jsh_mask & NSSBLACKHOLE_ATTR_SET_DEFAULT)) { + + return nssblackhole->jsh_set_default; + } + + return 0; +} + +/** @} */ + +static struct rtnl_tc_ops nssblackhole_ops = { + .to_kind = "nssblackhole", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_nssblackhole), + .to_msg_parser = nssblackhole_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = nssblackhole_dump_line, + [NL_DUMP_DETAILS] = nssblackhole_dump_details, + }, + .to_msg_fill = nssblackhole_msg_fill, +}; + +static void __init nssblackhole_init(void) +{ + rtnl_tc_register(&nssblackhole_ops); +} + +static void __exit nssblackhole_exit(void) +{ + rtnl_tc_unregister(&nssblackhole_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/nsshtb.c b/lib/route/qdisc/nsshtb.c new file mode 100644 index 0000000..31e520f --- /dev/null +++ b/lib/route/qdisc/nsshtb.c @@ -0,0 +1,550 @@ +/* + ************************************************************************** + * Copyright (c) 2014, 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_nsshtb HTB Scheduler (NSSHTB) + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define NSSHTB_CLASS_ATTR_RATE 0x001 +#define NSSHTB_CLASS_ATTR_BURST 0x002 +#define NSSHTB_CLASS_ATTR_CRATE 0x004 +#define NSSHTB_CLASS_ATTR_CBURST 0x008 +#define NSSHTB_CLASS_ATTR_QUANTUM 0x010 +#define NSSHTB_CLASS_ATTR_PRIORITY 0x020 +#define NSSHTB_CLASS_ATTR_OVERHEAD 0x040 +#define NSSHTB_QDISC_ATTR_R2Q 0x080 +/** @endcond */ + +static struct nla_policy nsshtb_policy[TCA_NSSHTB_MAX+1] = { + [TCA_NSSHTB_QDISC_PARMS] = { .minlen = sizeof(struct tc_nsshtb_qopt) }, + [TCA_NSSHTB_CLASS_PARMS] = { .minlen = sizeof(struct tc_nsshtb_class_qopt) }, +}; + +static struct nla_policy nsshtb_class_policy[TCA_NSSHTB_MAX+1] = { +}; + +static int nsshtb_qdisc_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_NSSHTB_MAX + 1]; + struct rtnl_nsshtb_qdisc *nsshtb = data; + struct tc_nsshtb_qopt *opts; + int err; + + if ((err = tca_parse(tb, TCA_NSSHTB_MAX, tc, nsshtb_policy)) < 0) + return err; + + if (tb[TCA_NSSHTB_QDISC_PARMS]) { + opts = nla_data(tb[TCA_NSSHTB_QDISC_PARMS]); + + nsshtb->wek_mask = 0; + + nsshtb->wek_r2q = opts->r2q; + nsshtb->wek_mask |= NSSHTB_QDISC_ATTR_R2Q; + } + + return 0; +} + +static int nsshtb_class_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_NSSHTB_MAX + 1]; + struct rtnl_nsshtb_class *nsshtb = data; + struct tc_nsshtb_class_qopt *opts; + int err; + + if ((err = tca_parse(tb, TCA_NSSHTB_MAX, tc, nsshtb_policy)) < 0) + return err; + + if (tb[TCA_NSSHTB_CLASS_PARMS]) { + opts = nla_data(tb[TCA_NSSHTB_CLASS_PARMS]); + + nsshtb->sud_mask = 0; + + nsshtb->sud_rate = opts->rate; + nsshtb->sud_mask |= NSSHTB_CLASS_ATTR_RATE; + + nsshtb->sud_burst = opts->burst; + nsshtb->sud_mask |= NSSHTB_CLASS_ATTR_BURST; + + nsshtb->sud_crate = opts->crate; + nsshtb->sud_mask |= NSSHTB_CLASS_ATTR_CRATE; + + nsshtb->sud_cburst = opts->cburst; + nsshtb->sud_mask |= NSSHTB_CLASS_ATTR_CBURST; + + nsshtb->sud_quantum = opts->quantum; + nsshtb->sud_mask |= NSSHTB_CLASS_ATTR_QUANTUM; + + nsshtb->sud_priority = opts->priority; + nsshtb->sud_mask |= NSSHTB_CLASS_ATTR_PRIORITY; + + nsshtb->sud_overhead = opts->overhead; + nsshtb->sud_mask |= NSSHTB_CLASS_ATTR_OVERHEAD; + } + + return 0; +} + +static void nsshtb_qdisc_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_nsshtb_qdisc *nsshtb = data; + + if (!nsshtb) + return; + + if (nsshtb->wek_mask & NSSHTB_QDISC_ATTR_R2Q) { + char buf[64]; + nl_dump(p, " r2q %s", + rtnl_tc_handle2str(nsshtb->wek_r2q, + buf, sizeof(buf))); + } +} + +static void nsshtb_class_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_nsshtb_class *nsshtb = data; + + if (!nsshtb) + return; + + if (nsshtb->sud_mask & NSSHTB_CLASS_ATTR_RATE) { + nl_dump(p, " Rate %u Crate %u", nsshtb->sud_rate, nsshtb->sud_crate); + } +} + +static int nsshtb_qdisc_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_nsshtb_qdisc *nsshtb = data; + struct tc_nsshtb_qopt opts; + + memset(&opts, 0, sizeof(opts)); + + if (nsshtb) { + if (nsshtb->wek_mask & NSSHTB_QDISC_ATTR_R2Q) + opts.r2q = nsshtb->wek_r2q; + } + + NLA_PUT(msg, TCA_NSSHTB_QDISC_PARMS, sizeof(opts), &opts); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static int nsshtb_class_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_nsshtb_class *nsshtb = data; + struct tc_nsshtb_class_qopt opts; + + if (!nsshtb) + return 0; + + memset(&opts, 0, sizeof(opts)); + + opts.rate = nsshtb->sud_rate; + opts.burst = nsshtb->sud_burst; + + if (nsshtb->sud_mask & NSSHTB_CLASS_ATTR_RATE) { + /* + * Burst is needed if Rate is specified + */ + if (!(nsshtb->sud_mask & NSSHTB_CLASS_ATTR_BURST)) + return -NLE_MISSING_ATTR; + + opts.rate = nsshtb->sud_rate; + opts.burst = nsshtb->sud_burst; + } + + if (nsshtb->sud_mask & NSSHTB_CLASS_ATTR_CRATE) { + /* + * Cburst is needed if Crate is specified + */ + if (!(nsshtb->sud_mask & NSSHTB_CLASS_ATTR_CBURST)) + return -NLE_MISSING_ATTR; + + opts.crate = nsshtb->sud_crate; + opts.cburst = nsshtb->sud_cburst; + } + + if (nsshtb->sud_mask & NSSHTB_CLASS_ATTR_QUANTUM) { + opts.quantum = nsshtb->sud_quantum; + } + + if (nsshtb->sud_mask & NSSHTB_CLASS_ATTR_PRIORITY) { + opts.priority = nsshtb->sud_priority; + } + + if (nsshtb->sud_mask & NSSHTB_CLASS_ATTR_OVERHEAD) { + opts.overhead = nsshtb->sud_overhead; + } + + NLA_PUT(msg, TCA_NSSHTB_CLASS_PARMS, sizeof(opts), &opts); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Attribute Access + * @{ + */ + +/** + * Set r2q of NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc to be modified + * @arg r2q New r2q for the qdisc + * @return 0 on success or a negative error code. + */ +int rtnl_nsshtb_qdisc_set_r2q(struct rtnl_qdisc *qdisc, uint16_t r2q) +{ + struct rtnl_nsshtb_qdisc *nsshtb_qdisc; + + if (!(nsshtb_qdisc = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + nsshtb_qdisc->wek_r2q = r2q; + nsshtb_qdisc->wek_mask |= NSSHTB_QDISC_ATTR_R2Q; + return 0; +} + +/** + * Get r2q of a NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc. + * @return r2q value. + */ +uint32_t rtnl_nsshtb_qdisc_get_r2q(struct rtnl_qdisc *qdisc) +{ + struct rtnl_nsshtb_qdisc *nsshtb_qdisc; + + if ((nsshtb_qdisc = rtnl_tc_data(TC_CAST(qdisc))) && + (nsshtb_qdisc->wek_mask & NSSHTB_QDISC_ATTR_R2Q)) { + + return nsshtb_qdisc->wek_r2q; + } + + return TC_H_UNSPEC; +} + +/** + * Set rate of NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc to be modified + * @arg rate New rate in bytes per second + * @return 0 on success or a negative error code. + */ +int rtnl_nsshtb_class_set_rate(struct rtnl_class *class, uint32_t rate) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if (!(nsshtb_class = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + nsshtb_class->sud_rate = rate; + nsshtb_class->sud_mask |= NSSHTB_CLASS_ATTR_RATE; + return 0; +} + +/** + * Get rate of a NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc. + * @return configured rate in bytes per second. + */ +uint32_t rtnl_nsshtb_class_get_rate(struct rtnl_class *class) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if ((nsshtb_class = rtnl_tc_data(TC_CAST(class))) && + (nsshtb_class->sud_mask & NSSHTB_CLASS_ATTR_RATE)) { + + return nsshtb_class->sud_rate; + } + + return 0; +} + +/** + * Set burst of NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc to be modified + * @arg burst New burst size in bytes. + * @return 0 on success or a negative error code. + */ +int rtnl_nsshtb_class_set_burst(struct rtnl_class *class, uint32_t burst) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if (!(nsshtb_class = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + nsshtb_class->sud_burst = burst; + nsshtb_class->sud_mask |= NSSHTB_CLASS_ATTR_BURST; + return 0; +} + +/** + * Get burst of a NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc. + * @return configured burst in bytes. + */ +uint32_t rtnl_nsshtb_class_get_burst(struct rtnl_class *class) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if ((nsshtb_class = rtnl_tc_data(TC_CAST(class))) && + (nsshtb_class->sud_mask & NSSHTB_CLASS_ATTR_BURST)) { + + return nsshtb_class->sud_burst; + } + + return 0; +} + +/** + * Set crate of NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc to be modified + * @arg crate New crate in bytes per second + * @return 0 on success or a negative error code. + */ +int rtnl_nsshtb_class_set_crate(struct rtnl_class *class, uint32_t crate) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if (!(nsshtb_class = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + nsshtb_class->sud_crate = crate; + nsshtb_class->sud_mask |= NSSHTB_CLASS_ATTR_CRATE; + return 0; +} + +/** + * Get crate of a NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc. + * @return configured crate in bytes per second. + */ +uint32_t rtnl_nsshtb_class_get_crate(struct rtnl_class *class) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if ((nsshtb_class = rtnl_tc_data(TC_CAST(class))) && + (nsshtb_class->sud_mask & NSSHTB_CLASS_ATTR_CRATE)) { + + return nsshtb_class->sud_crate; + } + + return 0; +} + +/** + * Set cburst of NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc to be modified + * @arg cburst New cburst size in bytes. + * @return 0 on success or a negative error code. + */ +int rtnl_nsshtb_class_set_cburst(struct rtnl_class *class, uint32_t cburst) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if (!(nsshtb_class = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + nsshtb_class->sud_cburst = cburst; + nsshtb_class->sud_mask |= NSSHTB_CLASS_ATTR_CBURST; + return 0; +} + +/** + * Get cburst of a NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc. + * @return configured cburst in bytes. + */ +uint32_t rtnl_nsshtb_class_get_cburst(struct rtnl_class *class) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if ((nsshtb_class = rtnl_tc_data(TC_CAST(class))) && + (nsshtb_class->sud_mask & NSSHTB_CLASS_ATTR_CBURST)) { + + return nsshtb_class->sud_cburst; + } + + return 0; +} + +/** + * Set quantum of NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc to be modified + * @arg quantum New quantum + * @return 0 on success or a negative error code. + */ +int rtnl_nsshtb_class_set_quantum(struct rtnl_class *class, uint32_t quantum) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if (!(nsshtb_class = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + nsshtb_class->sud_quantum = quantum; + nsshtb_class->sud_mask |= NSSHTB_CLASS_ATTR_QUANTUM; + return 0; +} + +/** + * Get quantum of a NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc. + * @return configured quantum + */ +uint32_t rtnl_nsshtb_class_get_quantum(struct rtnl_class *class) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if ((nsshtb_class = rtnl_tc_data(TC_CAST(class))) && + (nsshtb_class->sud_mask & NSSHTB_CLASS_ATTR_QUANTUM)) { + + return nsshtb_class->sud_quantum; + } + + return 0; +} + +/** + * Set priority of NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc to be modified + * @arg priority New priority in bytes + * @return 0 on success or a negative error code. + */ +int rtnl_nsshtb_class_set_priority(struct rtnl_class *class, uint32_t priority) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if (!(nsshtb_class = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + nsshtb_class->sud_priority = priority; + nsshtb_class->sud_mask |= NSSHTB_CLASS_ATTR_PRIORITY; + return 0; +} + +/** + * Get priority of a NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc. + * @return configured priority in bytes. + */ +uint32_t rtnl_nsshtb_class_get_priority(struct rtnl_class *class) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if ((nsshtb_class = rtnl_tc_data(TC_CAST(class))) && + (nsshtb_class->sud_mask & NSSHTB_CLASS_ATTR_PRIORITY)) { + + return nsshtb_class->sud_priority; + } + + return 0; +} + +/** + * Set overhead of NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc to be modified + * @arg overhead New overhead in bytes + * @return 0 on success or a negative error code. + */ +int rtnl_nsshtb_class_set_overhead(struct rtnl_class *class, uint32_t overhead) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if (!(nsshtb_class = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + nsshtb_class->sud_overhead = overhead; + nsshtb_class->sud_mask |= NSSHTB_CLASS_ATTR_OVERHEAD; + return 0; +} + +/** + * Get overhead of a NSSHTB qdisc. + * @arg qdisc NSSHTB qdisc. + * @return configured overhead in bytes. + */ +uint32_t rtnl_nsshtb_class_get_overhead(struct rtnl_class *class) +{ + struct rtnl_nsshtb_class *nsshtb_class; + + if ((nsshtb_class = rtnl_tc_data(TC_CAST(class))) && + (nsshtb_class->sud_mask & NSSHTB_CLASS_ATTR_OVERHEAD)) { + + return nsshtb_class->sud_overhead; + } + + return 0; +} + +/** @} */ + +static struct rtnl_tc_ops nsshtb_qdisc_ops = { + .to_kind = "nsshtb", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_nsshtb_qdisc), + .to_msg_parser = nsshtb_qdisc_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = nsshtb_qdisc_dump_line, + [NL_DUMP_DETAILS] = NULL, + }, + .to_msg_fill = nsshtb_qdisc_msg_fill, +}; + +static struct rtnl_tc_ops nsshtb_class_ops = { + .to_kind = "nsshtb", + .to_type = RTNL_TC_TYPE_CLASS, + .to_size = sizeof(struct rtnl_nsshtb_class), + .to_msg_parser = nsshtb_class_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = nsshtb_class_dump_line, + [NL_DUMP_DETAILS] = NULL, + }, + .to_msg_fill = nsshtb_class_msg_fill, +}; + +static void __init nsshtb_init(void) +{ + rtnl_tc_register(&nsshtb_qdisc_ops); + rtnl_tc_register(&nsshtb_class_ops); +} + +static void __exit nsshtb_exit(void) +{ + rtnl_tc_unregister(&nsshtb_class_ops); + rtnl_tc_unregister(&nsshtb_qdisc_ops); +} + +/** @} */