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 +#include + +#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 +#include + +#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 +#include + +#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 +#include + +#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 +#include + +#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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @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 +#include +#include +#include +#include +#include +#include +#include +#include + +/** @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 +#include +#include +#include +#include +#include +#include + +/** @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 +#include +#include +#include +#include +#include +#include + +/** @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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @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); +} + +/** @} */