| From 872a9a2601177b84257cdd9facc7e293d816278c Mon Sep 17 00:00:00 2001 |
| From: Kevin Cernekee <cernekee@chromium.org> |
| Date: Fri, 27 Jan 2017 14:59:13 -0800 |
| Subject: [PATCH] Jetstream: Support for NSS Qdiscs |
| |
| This patch is to support Qdiscs that shall |
| be implemened in the NSS QoS Engine. |
| |
| Kill this when the 3.14 kernel is deprecated |
| --- |
| include/uapi/linux/pkt_sched.h | 205 +++++ |
| tc/Makefile | 1 + |
| tc/q_nss.c | 1411 ++++++++++++++++++++++++++++++++ |
| 3 files changed, 1617 insertions(+) |
| create mode 100644 tc/q_nss.c |
| diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h |
| index 5011259b..d35dd7a2 100644 |
| --- a/include/uapi/linux/pkt_sched.h |
| +++ b/include/uapi/linux/pkt_sched.h |
| @@ -119,6 +119,211 @@ enum { |
| |
| #define TCA_STAB_MAX (__TCA_STAB_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 */ |
| +}; |
| + |
| +/* NSSWRED section */ |
| + |
| +enum { |
| + TCA_NSSWRED_UNSPEC, |
| + TCA_NSSWRED_PARMS, |
| + __TCA_NSSWRED_MAX |
| +}; |
| + |
| +#define TCA_NSSWRED_MAX (__TCA_NSSWRED_MAX - 1) |
| +#define NSSWRED_CLASS_MAX 6 |
| +struct tc_red_alg_parameter { |
| + __u32 min; /* qlen_avg < min: all pkts are enqueued */ |
| + __u32 max; /* qlen_avg > max: all pkts are dropped */ |
| + __u32 probability; /* Drop probability at qlen_avg = max */ |
| + __u32 exp_weight_factor; /* exp_weight_factor for calculate qlen_avg */ |
| +}; |
| + |
| +struct tc_nsswred_traffic_class { |
| + __u32 limit; /* Queue length */ |
| + __u32 weight_mode_value; /* Weight mode value */ |
| + struct tc_red_alg_parameter rap;/* Parameters for RED alg */ |
| +}; |
| + |
| +/* |
| + * Weight modes for WRED |
| + */ |
| +enum tc_nsswred_weight_modes { |
| + TC_NSSWRED_WEIGHT_MODE_DSCP = 0, /* Weight mode is DSCP */ |
| + TC_NSSWRED_WEIGHT_MODES, /* Must be last */ |
| +}; |
| +typedef enum tc_nsswred_weight_modes tc_nsswred_weight_mode_t; |
| + |
| +struct tc_nsswred_qopt { |
| + __u32 limit; /* Queue length */ |
| + tc_nsswred_weight_mode_t weight_mode; /* Weight mode */ |
| + __u32 traffic_classes; /* How many traffic classes: DPs */ |
| + __u32 def_traffic_class; /* Default traffic if no match: def_DP */ |
| + __u32 traffic_id; /* The traffic id to be configured */ |
| + __u32 weight_mode_value; /* Weight mode value */ |
| + struct tc_red_alg_parameter rap; /* RED algorithm parameters */ |
| + struct tc_nsswred_traffic_class tntc[NSSWRED_CLASS_MAX]; |
| + /* Traffic settings for dumpping */ |
| + __u8 ecn; /* Setting ECN bit or dropping */ |
| + __u8 set_default; /* Sets qdisc to be the default 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 the associated interface */ |
| + __u32 quantum; /* Quamtum allocation for DRR */ |
| +}; |
| + |
| +struct tc_nssbf_qopt { |
| + __u16 defcls; /* Default class value */ |
| +}; |
| + |
| +/* NSSWRR section */ |
| + |
| +enum { |
| + TCA_NSSWRR_UNSPEC, |
| + TCA_NSSWRR_CLASS_PARMS, |
| + __TCA_NSSWRR_MAX |
| +}; |
| + |
| +#define TCA_NSSWRR_MAX (__TCA_NSSWRR_MAX - 1) |
| + |
| +struct tc_nsswrr_class_qopt { |
| + __u32 quantum; /* Weight associated to this class */ |
| +}; |
| + |
| +/* NSSWFQ section */ |
| + |
| +enum { |
| + TCA_NSSWFQ_UNSPEC, |
| + TCA_NSSWFQ_CLASS_PARMS, |
| + __TCA_NSSWFQ_MAX |
| +}; |
| + |
| +#define TCA_NSSWFQ_MAX (__TCA_NSSWFQ_MAX - 1) |
| + |
| +struct tc_nsswfq_class_qopt { |
| + __u32 quantum; /* Weight associated to this class */ |
| +}; |
| + |
| +/* 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; /* Allowed burst size */ |
| + __u32 rate; /* Allowed bandwidth for this class */ |
| + __u32 cburst; /* Maximum burst size */ |
| + __u32 crate; /* Maximum bandwidth for this class */ |
| + __u32 quantum; /* Quantum allocation 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 */ |
| +}; |
| + |
| +/* 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 */ |
| +}; |
| + |
| /* FIFO section */ |
| |
| struct tc_fifo_qopt { |
| diff --git a/tc/Makefile b/tc/Makefile |
| index 14171a28..457a3ea1 100644 |
| --- a/tc/Makefile |
| +++ b/tc/Makefile |
| @@ -72,6 +72,7 @@ TCMODULES += q_fq.o |
| TCMODULES += q_pie.o |
| TCMODULES += q_cake.o |
| TCMODULES += q_hhf.o |
| +TCMODULES += q_nss.o |
| TCMODULES += q_clsact.o |
| TCMODULES += e_bpf.o |
| TCMODULES += f_matchall.o |
| diff --git a/tc/q_nss.c b/tc/q_nss.c |
| new file mode 100644 |
| index 00000000..e84166d6 |
| --- /dev/null |
| +++ b/tc/q_nss.c |
| @@ -0,0 +1,1411 @@ |
| +/* |
| + ************************************************************************** |
| + * 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 <stdio.h> |
| +#include <stdlib.h> |
| +#include <unistd.h> |
| +#include <syslog.h> |
| +#include <fcntl.h> |
| +#include <sys/socket.h> |
| +#include <netinet/in.h> |
| +#include <arpa/inet.h> |
| +#include <string.h> |
| +#include <math.h> |
| + |
| +#include "utils.h" |
| +#include "tc_util.h" |
| +#include "tc_red.h" |
| + |
| +/* ======================== NSSWRED =======================*/ |
| + |
| +static void nssred_explain(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nssred limit BYTES avpkt BYTES [ min BYTES ] [ max BYTES ] [ probability VALUE ]\n"); |
| + fprintf(stderr, " [ burst PACKETS ] [ecn] [ set_default ]\n"); |
| +} |
| + |
| +static void nsswred_explain(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nsswred setup DPs NUMBER dp_default NUMBER [ weight_mode dscp ] [ecn] [ set_default ]\n"); |
| + fprintf(stderr, " nsswred limit BYTES DP NUMBER min BYTES max BYTES avpkt BYTES dscp NUMBER [ probability VALUE ] [ burst PACKETS ]\n"); |
| +} |
| + |
| +static int nsswred_setup(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + struct rtattr *tail; |
| + struct tc_nsswred_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + unsigned int dps = 0; |
| + unsigned int def_dp = 0; |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "DPs") == 0) { |
| + NEXT_ARG(); |
| + if (get_unsigned(&dps, *argv, 0) || dps > NSSWRED_CLASS_MAX) { |
| + |
| + fprintf(stderr, "NSSWRED: DPs should be between 1 - %d\n", NSSWRED_CLASS_MAX); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "weight_mode") == 0) { |
| + NEXT_ARG(); |
| + if (strcmp(*argv, "dscp") == 0) { |
| + opt.weight_mode = TC_NSSWRED_WEIGHT_MODE_DSCP; |
| + } else { |
| + fprintf(stderr, "Illegal \"weight_mode\", we only support dscp at this moment\n"); |
| + } |
| + } else if (strcmp(*argv, "ecn") == 0) { |
| + opt.ecn = 1; |
| + } else if (strcmp(*argv, "dp_default") == 0) { |
| + NEXT_ARG(); |
| + if (get_unsigned(&def_dp, *argv, 0) || def_dp > dps) { |
| + fprintf(stderr, "NSSWRED: Illegal dp_default value\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nsswred_explain(); |
| + return -1; |
| + } else if (strcmp(*argv, "set_default") == 0) { |
| + opt.set_default = 1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nsswred_explain(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (!dps || !def_dp) { |
| + fprintf(stderr, "NSSWRED: Illegal nsswred setup parameters\n"); |
| + return -1; |
| + } |
| + opt.traffic_classes = dps; |
| + opt.def_traffic_class = def_dp; |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSWRED_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nsswred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + struct rtattr *tail; |
| + struct tc_nsswred_qopt opt; |
| + |
| + int total_args = argc; |
| + unsigned burst = 0; |
| + unsigned avpkt = 0; |
| + double probability = 0.0; |
| + unsigned char weighted = (strcmp(qu->id, "nsswred") == 0); |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "limit") == 0) { |
| + NEXT_ARG(); |
| + if (get_size(&opt.limit, *argv)) { |
| + fprintf(stderr, "Illegal \"limit\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "set_default") == 0) { |
| + opt.set_default = 1; |
| + } else if (strcmp(*argv, "min") == 0) { |
| + NEXT_ARG(); |
| + if (get_size(&opt.rap.min, *argv)) { |
| + fprintf(stderr, "Illegal \"min\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "max") == 0) { |
| + NEXT_ARG(); |
| + if (get_size(&opt.rap.max, *argv)) { |
| + fprintf(stderr, "Illegal \"max\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "burst") == 0) { |
| + NEXT_ARG(); |
| + if (get_unsigned(&burst, *argv, 0)) { |
| + fprintf(stderr, "Illegal \"burst\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "avpkt") == 0) { |
| + NEXT_ARG(); |
| + if (get_size(&avpkt, *argv)) { |
| + fprintf(stderr, "Illegal \"avpkt\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "probability") == 0) { |
| + NEXT_ARG(); |
| + if (sscanf(*argv, "%lg", &probability) != 1) { |
| + fprintf(stderr, "Illegal \"probability\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "ecn") == 0) { |
| + opt.ecn = 1; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + if (weighted) { |
| + nsswred_explain(); |
| + } else { |
| + nssred_explain(); |
| + } |
| + return -1; |
| + } else if (weighted) { |
| + if (strcmp(*argv, "setup") == 0) { |
| + if (argc != total_args) { |
| + fprintf(stderr, "Setup command must be the first parameter\n"); |
| + return -1; |
| + } |
| + return nsswred_setup(qu, argc-1, argv+1, n); |
| + } else if (strcmp(*argv, "DP") == 0) { |
| + NEXT_ARG(); |
| + if (get_unsigned(&opt.traffic_id, *argv, 0)) { |
| + fprintf(stderr, "Illegal \"DP\""); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "dscp") == 0) { |
| + NEXT_ARG(); |
| + if (get_unsigned(&opt.weight_mode_value, *argv, 0)) { |
| + fprintf(stderr, "Illegal \"dscp\" value\n"); |
| + return -1; |
| + } |
| + } |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + if (weighted) { |
| + nsswred_explain(); |
| + } else { |
| + nssred_explain(); |
| + } |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (weighted) { |
| + if (!opt.limit || !opt.rap.min || !opt.rap.max || !opt.traffic_id || !avpkt || !opt.weight_mode_value) { |
| + fprintf(stderr, "NSSWRED: Require limit, min, max, avpkt, DP, weight_mode_value\n"); |
| + return -1; |
| + } |
| + } else { |
| + if (!opt.limit || !avpkt) { |
| + fprintf(stderr, "NSSRED: Require limit, avpkt"); |
| + return -1; |
| + } |
| + } |
| + |
| + /* |
| + * Compute default min/max thresholds based on |
| + * Sally Floyd's recommendations: |
| + * http://www.icir.org/floyd/REDparameters.txt |
| + */ |
| + if (!opt.rap.max) |
| + opt.rap.max = opt.rap.min ? opt.rap.min * 3 : opt.limit / 4; |
| + if (!opt.rap.min) |
| + opt.rap.min = opt.rap.max / 3; |
| + if (!burst) |
| + burst = (2 * opt.rap.min + opt.rap.max) / (3 * avpkt); |
| + if ((opt.rap.exp_weight_factor = tc_red_eval_ewma(opt.rap.min, burst, avpkt)) < 0) { |
| + fprintf(stderr, "RED: failed to calculate EWMA constant.\n"); |
| + return -1; |
| + } |
| + |
| + /* |
| + * project [0.0-1.0] to [0-255] to avoid floating point calculation |
| + */ |
| + opt.rap.probability = probability * (pow(2, 8)-1); |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSWRED_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nsswred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSWRED_MAX + 1]; |
| + struct tc_nsswred_qopt *qopt; |
| + int i; |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSWRED_MAX, opt); |
| + |
| + if (tb[TCA_NSSWRED_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSWRED_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSWRED_PARMS]); |
| + |
| + if (strcmp(qu->id, "nsswred") == 0) { |
| + fprintf(f, "DPs %d def_DP %d weight mode: " , qopt->traffic_classes, qopt->def_traffic_class); |
| + if (qopt->weight_mode == TC_NSSWRED_WEIGHT_MODE_DSCP) |
| + fprintf(f, "DSCP\n"); |
| + else |
| + fprintf(f, "Unknown\n"); |
| + for (i = 0;i < qopt->traffic_classes; i ++) { |
| + if (qopt->tntc[i].rap.exp_weight_factor) { |
| + double prob = (double)qopt->tntc[i].rap.probability; |
| + fprintf(f, "DP %d: limit %d, weight mode value: %d min: %d max: %d exp_weight_factor: %d probability %.2f\n", i+1, qopt->tntc[i].limit, qopt->tntc[i].weight_mode_value |
| + , qopt->tntc[i].rap.min,qopt->tntc[i].rap.max,qopt->tntc[i].rap.exp_weight_factor,prob/255); |
| + } |
| + } |
| + } else { |
| + double prob = (double)qopt->rap.probability; |
| + fprintf(f, "limit %d, min: %d max: %d exp_weight_factor: %d probability %.2f\n", qopt->limit, qopt->rap.min,qopt->rap.max,qopt->rap.exp_weight_factor,prob/255); |
| + } |
| + |
| + if (qopt->ecn) |
| + fprintf(f, "ECN enabled "); |
| + if (qopt->set_default) |
| + fprintf(f, "set_default "); |
| + |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nssred_qdisc_util = { |
| + .id = "nssred", |
| + .parse_qopt = nsswred_parse_opt, |
| + .print_qopt = nsswred_print_opt, |
| +}; |
| + |
| +struct qdisc_util nsswred_qdisc_util = { |
| + .id = "nsswred", |
| + .parse_qopt = nsswred_parse_opt, |
| + .print_qopt = nsswred_print_opt, |
| +}; |
| + |
| +/* ======================== NSSFIFO =======================*/ |
| + |
| +static void nssfifo_explain(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nsspfifo [ limit PACKETS ] [ set_default ]\n"); |
| +} |
| + |
| +static int nssfifo_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + struct rtattr *tail; |
| + struct tc_nssfifo_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "limit") == 0) { |
| + NEXT_ARG(); |
| + if (get_size(&opt.limit, *argv) || opt.limit == 0) { |
| + fprintf(stderr, "Illegal \"limit\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "set_default") == 0) { |
| + opt.set_default = 1; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nssfifo_explain(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nssfifo_explain(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSFIFO_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nssfifo_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSFIFO_MAX + 1]; |
| + struct tc_nssfifo_qopt *qopt; |
| + SPRINT_BUF(b1); |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSFIFO_MAX, opt); |
| + |
| + if (tb[TCA_NSSFIFO_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSFIFO_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSFIFO_PARMS]); |
| + |
| + if (strcmp(qu->id, "nssbfifo") == 0) |
| + fprintf(f, "limit %s ", sprint_size(qopt->limit, b1)); |
| + else |
| + fprintf(f, "limit %up ", qopt->limit); |
| + |
| + if (qopt->set_default) |
| + fprintf(f, "set_default "); |
| + |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nsspfifo_qdisc_util = { |
| + .id = "nsspfifo", |
| + .parse_qopt = nssfifo_parse_opt, |
| + .print_qopt = nssfifo_print_opt, |
| +}; |
| + |
| +struct qdisc_util nssbfifo_qdisc_util = { |
| + .id = "nssbfifo", |
| + .parse_qopt = nssfifo_parse_opt, |
| + .print_qopt = nssfifo_print_opt, |
| +}; |
| + |
| +/* ======================== NSSCODEL =======================*/ |
| + |
| +static void nsscodel_explain(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nsscodel target TIME interval TIME [ limit PACKETS ] [ set_default ]\n"); |
| +} |
| + |
| +static void nsscodel_explain_err1(void) |
| +{ |
| + fprintf(stderr, "Value of target and interval should be greater than 1ms\n"); |
| +} |
| + |
| +static int nsscodel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + struct rtattr *tail; |
| + struct tc_nsscodel_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "target") == 0) { |
| + NEXT_ARG(); |
| + if (get_time(&opt.target, *argv)) { |
| + fprintf(stderr, "Illegal \"target\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "limit") == 0) { |
| + NEXT_ARG(); |
| + if (get_size(&opt.limit, *argv) || opt.limit == 0) { |
| + fprintf(stderr, "Illegal \"limit\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "interval") == 0) { |
| + NEXT_ARG(); |
| + if (get_time(&opt.interval, *argv)) { |
| + fprintf(stderr, "Illegal \"interval\"\n"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "set_default") == 0) { |
| + opt.set_default = 1; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nsscodel_explain(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nsscodel_explain(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (!opt.target || !opt.interval) { |
| + nsscodel_explain(); |
| + return -1; |
| + } |
| + |
| + if (opt.target < 1000 || opt.interval < 1000) { |
| + nsscodel_explain_err1(); |
| + return -1; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSCODEL_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nsscodel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSCODEL_MAX + 1]; |
| + struct tc_nsscodel_qopt *qopt; |
| + SPRINT_BUF(b1); |
| + SPRINT_BUF(b2); |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSCODEL_MAX, opt); |
| + |
| + if (tb[TCA_NSSCODEL_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSCODEL_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSCODEL_PARMS]); |
| + |
| + fprintf(f, "target %s limit %up interval %s ", |
| + sprint_time(qopt->target, b1), |
| + qopt->limit, |
| + sprint_time(qopt->interval, b2)); |
| + |
| + if (qopt->set_default) |
| + fprintf(f, "set_default "); |
| + |
| + return 0; |
| +} |
| + |
| +static int nsscodel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) |
| +{ |
| + struct tc_nsscodel_xstats *st; |
| + |
| + if (xstats == NULL) |
| + return 0; |
| + |
| + if (RTA_PAYLOAD(xstats) < sizeof(*st)) |
| + return -1; |
| + |
| + st = RTA_DATA(xstats); |
| + fprintf(f, " peak queue delay %ums peak drop delay %ums", |
| + st->peak_queue_delay, st->peak_drop_delay); |
| + |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nsscodel_qdisc_util = { |
| + .id = "nsscodel", |
| + .parse_qopt = nsscodel_parse_opt, |
| + .print_qopt = nsscodel_print_opt, |
| + .print_xstats = nsscodel_print_xstats, |
| +}; |
| + |
| +/* ======================== NSSTBL =======================*/ |
| + |
| +static void nsstbl_explain(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nsstbl burst BYTES rate BPS [ mtu BYTES ]\n"); |
| +} |
| + |
| +static int nsstbl_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + int ok = 0; |
| + struct rtattr *tail; |
| + struct tc_nsstbl_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "burst") == 0 || |
| + strcmp(*argv, "buffer") == 0 || |
| + strcmp(*argv, "maxburst") == 0) { |
| + NEXT_ARG(); |
| + if (opt.burst) { |
| + fprintf(stderr, "Double \"buffer/burst\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.burst, *argv)) { |
| + fprintf(stderr, "Illegal \"burst\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "mtu") == 0 || |
| + strcmp(*argv, "minburst") == 0) { |
| + NEXT_ARG(); |
| + if (opt.mtu) { |
| + fprintf(stderr, "Double \"mtu/minburst\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.mtu, *argv)) { |
| + fprintf(stderr, "Illegal \"mtu\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "rate") == 0) { |
| + NEXT_ARG(); |
| + if (opt.rate) { |
| + fprintf(stderr, "Double \"rate\" spec\n"); |
| + return -1; |
| + } |
| + if (get_rate(&opt.rate, *argv)) { |
| + fprintf(stderr, "Illegal \"rate\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nsstbl_explain(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nsstbl_explain(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (!ok) { |
| + nsstbl_explain(); |
| + return -1; |
| + } |
| + |
| + if (!opt.rate || !opt.burst) { |
| + fprintf(stderr, "Both \"rate\" and \"burst\" are required.\n"); |
| + return -1; |
| + } |
| + |
| + if (opt.peakrate) { |
| + if (!opt.mtu) { |
| + fprintf(stderr, "\"mtu\" is required, if \"peakrate\" is requested.\n"); |
| + return -1; |
| + } |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSTBL_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nsstbl_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSTBL_MAX + 1]; |
| + struct tc_nsstbl_qopt *qopt; |
| + SPRINT_BUF(b1); |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSTBL_MAX, opt); |
| + |
| + if (tb[TCA_NSSTBL_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSTBL_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSTBL_PARMS]); |
| + |
| + fprintf(f, "buffer/maxburst %s ", sprint_size(qopt->burst, b1)); |
| + fprintf(f, "rate %s ", sprint_rate(qopt->rate, b1)); |
| + fprintf(f, "peakrate %s ", sprint_rate(qopt->peakrate, b1)); |
| + fprintf(f, "mtu/minburst %s ", sprint_size(qopt->mtu, b1)); |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nsstbl_qdisc_util = { |
| + .id = "nsstbl", |
| + .parse_qopt = nsstbl_parse_opt, |
| + .print_qopt = nsstbl_print_opt, |
| +}; |
| + |
| +/* ======================== NSSPRIO =======================*/ |
| + |
| +static void nssprio_explain(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nssprio [ bands NUMBER (default 256) ]\n"); |
| +} |
| + |
| +static int nssprio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + int ok = 0; |
| + struct rtattr *tail; |
| + struct tc_nssprio_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "bands") == 0) { |
| + NEXT_ARG(); |
| + if (get_integer(&opt.bands, *argv, 10)) { |
| + fprintf(stderr, "Illegal \"limit\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nssprio_explain(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nssprio_explain(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (!ok) { |
| + opt.bands = TCA_NSSPRIO_MAX_BANDS; |
| + } else if (opt.bands > TCA_NSSPRIO_MAX_BANDS) { |
| + nssprio_explain(); |
| + return -1; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSPRIO_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nssprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSPRIO_MAX + 1]; |
| + struct tc_nssprio_qopt *qopt; |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSPRIO_MAX, opt); |
| + |
| + if (tb[TCA_NSSPRIO_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSPRIO_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSPRIO_PARMS]); |
| + |
| + fprintf(f, "bands %u ", qopt->bands); |
| + |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nssprio_qdisc_util = { |
| + .id = "nssprio", |
| + .parse_qopt = nssprio_parse_opt, |
| + .print_qopt = nssprio_print_opt, |
| +}; |
| + |
| +/* ======================== NSSBF =======================*/ |
| + |
| +static void nssbf_explain_qdisc(void) |
| +{ |
| + fprintf(stderr, |
| + "Usage: ... nssbf \n" |
| + ); |
| +} |
| + |
| +static void nssbf_explain_class(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nssbf rate BPS burst BYTES [ mtu BYTES ]\n"); |
| + fprintf(stderr, " [ quantum BYTES ]\n"); |
| +} |
| + |
| +static void nssbf_explain1(char *arg) |
| +{ |
| + fprintf(stderr, "NSSBF: Illegal \"%s\"\n", arg); |
| +} |
| + |
| +static int nssbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + struct tc_nssbf_qopt opt; |
| + struct rtattr *tail; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (matches(*argv, "default") == 0) { |
| + NEXT_ARG(); |
| + if (opt.defcls != 0) { |
| + fprintf(stderr, "NSSBF: Double \"default\"\n"); |
| + return -1; |
| + } |
| + if (get_u16(&opt.defcls, *argv, 16) < 0) { |
| + nssbf_explain1("default"); |
| + return -1; |
| + } |
| + } else if (matches(*argv, "help") == 0) { |
| + nssbf_explain_qdisc(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "NSSBF: What is \"%s\" ?\n", *argv); |
| + nssbf_explain_qdisc(); |
| + return -1; |
| + } |
| + argc--, argv++; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSBF_QDISC_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nssbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct tc_nssbf_qopt *qopt; |
| + |
| + if (opt == NULL) |
| + return 0; |
| + if (RTA_PAYLOAD(opt) < sizeof(*qopt)) |
| + return -1; |
| + qopt = RTA_DATA(opt); |
| + |
| + if (qopt->defcls != 0) |
| + fprintf(f, "default %x ", qopt->defcls); |
| + |
| + return 0; |
| +} |
| + |
| +static int nssbf_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + int ok = 0; |
| + struct rtattr *tail; |
| + struct tc_nssbf_class_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "burst") == 0 || |
| + strcmp(*argv, "buffer") == 0 || |
| + strcmp(*argv, "maxburst") == 0) { |
| + NEXT_ARG(); |
| + if (opt.burst) { |
| + fprintf(stderr, "Double \"buffer/burst\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.burst, *argv)) { |
| + fprintf(stderr, "Illegal \"burst\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "mtu") == 0) { |
| + NEXT_ARG(); |
| + if (opt.mtu) { |
| + fprintf(stderr, "Double \"mtu\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.mtu, *argv)) { |
| + fprintf(stderr, "Illegal \"mtu\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "quantum") == 0) { |
| + NEXT_ARG(); |
| + if (opt.quantum) { |
| + fprintf(stderr, "Double \"quantum\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.quantum, *argv)) { |
| + fprintf(stderr, "Illegal \"quantum\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "rate") == 0) { |
| + NEXT_ARG(); |
| + if (opt.rate) { |
| + fprintf(stderr, "Double \"rate\" spec\n"); |
| + return -1; |
| + } |
| + if (get_rate(&opt.rate, *argv)) { |
| + fprintf(stderr, "Illegal \"rate\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nssbf_explain_class(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nssbf_explain_class(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (!ok) { |
| + nssbf_explain_class(); |
| + return -1; |
| + } |
| + |
| + if (!opt.rate || !opt.burst) { |
| + fprintf(stderr, "Both \"rate\" and \"burst\" are required.\n"); |
| + return -1; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSBF_CLASS_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nssbf_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSBF_MAX + 1]; |
| + struct tc_nssbf_class_qopt *qopt; |
| + SPRINT_BUF(b1); |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSBF_MAX, opt); |
| + |
| + if (tb[TCA_NSSBF_CLASS_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSBF_CLASS_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSBF_CLASS_PARMS]); |
| + |
| + fprintf(f, "burst %s ", sprint_size(qopt->burst, b1)); |
| + fprintf(f, "rate %s ", sprint_rate(qopt->rate, b1)); |
| + fprintf(f, "quantum %s ", sprint_size(qopt->quantum, b1)); |
| + fprintf(f, "mtu %s ", sprint_size(qopt->mtu, b1)); |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nssbf_qdisc_util = { |
| + .id = "nssbf", |
| + .parse_qopt = nssbf_parse_opt, |
| + .print_qopt = nssbf_print_opt, |
| + .parse_copt = nssbf_parse_class_opt, |
| + .print_copt = nssbf_print_class_opt, |
| +}; |
| + |
| +/* ======================== NSSWRR =======================*/ |
| + |
| +static void nsswrr_explain_qdisc(void) |
| +{ |
| + fprintf(stderr, |
| + "Usage (qdisc): ... nsswrr\n" |
| + "\n" |
| + "nsswrr qdisc does not take in any parameters\n" |
| + ); |
| +} |
| + |
| +static void nsswrr_explain_class(void) |
| +{ |
| + fprintf(stderr, "Usage (class): ... nsswrr quantum PACKETS ]\n"); |
| +} |
| + |
| +static int nsswrr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + while (argc > 0) { |
| + if (matches(*argv, "help") == 0) { |
| + nsswrr_explain_qdisc(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "NSSWRR: What is \"%s\" ?\n", *argv); |
| + nsswrr_explain_qdisc(); |
| + return -1; |
| + } |
| + argc--, argv++; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int nsswrr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + /* |
| + * We currently dont have any parameters to print |
| + */ |
| + |
| + return 0; |
| +} |
| + |
| +static int nsswrr_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + int ok = 0; |
| + struct rtattr *tail; |
| + struct tc_nsswrr_class_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "quantum") == 0) { |
| + NEXT_ARG(); |
| + if (get_u32(&opt.quantum, *argv, 10)) { |
| + fprintf(stderr, "Illegal \"quantum\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nsswrr_explain_class(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nsswrr_explain_class(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (!ok) { |
| + nsswrr_explain_class(); |
| + return -1; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSWRR_CLASS_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nsswrr_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSWRR_MAX + 1]; |
| + struct tc_nsswrr_class_qopt *qopt; |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSWRR_MAX, opt); |
| + |
| + if (tb[TCA_NSSWRR_CLASS_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSWRR_CLASS_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSWRR_CLASS_PARMS]); |
| + |
| + fprintf(f, "quantum %up ", qopt->quantum); |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nsswrr_qdisc_util = { |
| + .id = "nsswrr", |
| + .parse_qopt = nsswrr_parse_opt, |
| + .print_qopt = nsswrr_print_opt, |
| + .parse_copt = nsswrr_parse_class_opt, |
| + .print_copt = nsswrr_print_class_opt, |
| +}; |
| + |
| +/* ======================== NSSWFQ =======================*/ |
| + |
| +static void nsswfq_explain_qdisc(void) |
| +{ |
| + fprintf(stderr, |
| + "Usage (qdisc): ... nsswfq\n" |
| + "\n" |
| + "nsswfq qdisc does not take in any parameters\n" |
| + ); |
| +} |
| + |
| +static void nsswfq_explain_class(void) |
| +{ |
| + fprintf(stderr, "Usage (class): ... nsswfq quantum BYTES ]\n"); |
| +} |
| + |
| +static int nsswfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + while (argc > 0) { |
| + if (matches(*argv, "help") == 0) { |
| + nsswfq_explain_qdisc(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "NSSWFQ: What is \"%s\" ?\n", *argv); |
| + nsswfq_explain_qdisc(); |
| + return -1; |
| + } |
| + argc--, argv++; |
| + } |
| + return 0; |
| +} |
| + |
| +static int nsswfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + /* |
| + * We currently dont have any parameters to print |
| + */ |
| + return 0; |
| +} |
| + |
| +static int nsswfq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + int ok = 0; |
| + struct rtattr *tail; |
| + struct tc_nsswfq_class_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "quantum") == 0) { |
| + NEXT_ARG(); |
| + if (get_u32(&opt.quantum, *argv, 10)) { |
| + fprintf(stderr, "Illegal \"quantum\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nsswfq_explain_class(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nsswfq_explain_class(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (!ok) { |
| + nsswfq_explain_class(); |
| + return -1; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSWFQ_CLASS_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nsswfq_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSWFQ_MAX + 1]; |
| + struct tc_nsswfq_class_qopt *qopt; |
| + SPRINT_BUF(b1); |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSWFQ_MAX, opt); |
| + |
| + if (tb[TCA_NSSWFQ_CLASS_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSWFQ_CLASS_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSWFQ_CLASS_PARMS]); |
| + |
| + fprintf(f, "quantum %s ", sprint_size(qopt->quantum, b1)); |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nsswfq_qdisc_util = { |
| + .id = "nsswfq", |
| + .parse_qopt = nsswfq_parse_opt, |
| + .print_qopt = nsswfq_print_opt, |
| + .parse_copt = nsswfq_parse_class_opt, |
| + .print_copt = nsswfq_print_class_opt, |
| +}; |
| + |
| +/* ======================== NSSHTB =======================*/ |
| + |
| +static void nsshtb_explain_qdisc(void) |
| +{ |
| + fprintf(stderr, |
| + "Usage: ... nsshtb [ r2q ]\n" |
| + ); |
| +} |
| + |
| +static void nsshtb_explain_class(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nsshtb priority 0-3 [ quantum BYTES ] [ rate BPS ] [ burst BYTES ] [crate BPS ] [ cburst BYTES ]\n"); |
| + fprintf(stderr, " [ overhead BYTES ] \n"); |
| +} |
| + |
| +static void nsshtb_explain1(char *arg) |
| +{ |
| + fprintf(stderr, "NSSHTB: Illegal \"%s\"\n", arg); |
| +} |
| + |
| +static int nsshtb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + struct tc_nsshtb_qopt opt; |
| + struct rtattr *tail; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "r2q") == 0) { |
| + NEXT_ARG(); |
| + if (opt.r2q != 0) { |
| + fprintf(stderr, "NSSHTB: Double \"r2q\"\n"); |
| + return -1; |
| + } |
| + if (get_u32(&opt.r2q, *argv, 10) < 0) { |
| + nsshtb_explain1("r2q"); |
| + return -1; |
| + } |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nsshtb_explain_qdisc(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "NSSHTB: What is \"%s\" ?\n", *argv); |
| + nsshtb_explain_qdisc(); |
| + return -1; |
| + } |
| + argc--, argv++; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSHTB_QDISC_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nsshtb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct tc_nsshtb_qopt *qopt; |
| + |
| + if (opt == NULL) |
| + return 0; |
| + if (RTA_PAYLOAD(opt) < sizeof(*qopt)) |
| + return -1; |
| + qopt = RTA_DATA(opt); |
| + |
| + if (qopt->r2q != 0) |
| + fprintf(f, "r2q %x ", qopt->r2q); |
| + |
| + return 0; |
| +} |
| + |
| +static int nsshtb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + int ok = 0; |
| + struct rtattr *tail; |
| + struct tc_nsshtb_class_qopt opt; |
| + int crate = 0; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "burst") == 0) { |
| + NEXT_ARG(); |
| + if (opt.burst) { |
| + fprintf(stderr, "Double \"burst\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.burst, *argv)) { |
| + fprintf(stderr, "Illegal \"burst\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "rate") == 0) { |
| + NEXT_ARG(); |
| + if (opt.rate) { |
| + fprintf(stderr, "Double \"rate\" spec\n"); |
| + return -1; |
| + } |
| + if (get_rate(&opt.rate, *argv)) { |
| + fprintf(stderr, "Illegal \"rate\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "cburst") == 0) { |
| + NEXT_ARG(); |
| + if (opt.cburst) { |
| + fprintf(stderr, "Double \"cburst\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.cburst, *argv)) { |
| + fprintf(stderr, "Illegal \"cburst\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "crate") == 0) { |
| + NEXT_ARG(); |
| + if (opt.crate) { |
| + fprintf(stderr, "Double \"crate\" spec\n"); |
| + return -1; |
| + } |
| + if (get_rate(&opt.crate, *argv)) { |
| + fprintf(stderr, "Illegal \"crate\"\n"); |
| + return -1; |
| + } |
| + crate++; |
| + ok++; |
| + } else if (strcmp(*argv, "priority") == 0) { |
| + NEXT_ARG(); |
| + if (opt.priority) { |
| + fprintf(stderr, "Double \"priority\" spec\n"); |
| + return -1; |
| + } |
| + if (get_u32(&opt.priority, *argv, 10) < 0) { |
| + fprintf(stderr, "Illegal \"priority\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "quantum") == 0) { |
| + NEXT_ARG(); |
| + if (opt.quantum) { |
| + fprintf(stderr, "Double \"quantum\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.quantum, *argv)) { |
| + fprintf(stderr, "Illegal \"quantum\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "overhead") == 0) { |
| + NEXT_ARG(); |
| + if (opt.overhead) { |
| + fprintf(stderr, "Double \"overhead\" spec\n"); |
| + return -1; |
| + } |
| + if (get_size(&opt.overhead, *argv)) { |
| + fprintf(stderr, "Illegal \"overhead\"\n"); |
| + return -1; |
| + } |
| + ok++; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nsshtb_explain_class(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nsshtb_explain_class(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + if (!ok) { |
| + nsshtb_explain_class(); |
| + return -1; |
| + } |
| + |
| + if (opt.rate && !opt.burst) { |
| + fprintf(stderr, "\"burst\" required if \"rate\" is specified.\n"); |
| + return -1; |
| + } |
| + |
| + if (!crate) { |
| + fprintf(stderr, "\"crate\" is required.\n"); |
| + return -1; |
| + } |
| + |
| + if (opt.crate && !opt.cburst) { |
| + fprintf(stderr, "\"cburst\" required if \"crate\" is non-zero.\n"); |
| + return -1; |
| + } |
| + |
| + if (opt.priority > 3) { |
| + fprintf(stderr, "\"priority\" should be an integer between 0 and 3.\n"); |
| + return -1; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSHTB_CLASS_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nsshtb_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSHTB_MAX + 1]; |
| + struct tc_nsshtb_class_qopt *qopt; |
| + SPRINT_BUF(b1); |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSHTB_MAX, opt); |
| + |
| + if (tb[TCA_NSSHTB_CLASS_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSHTB_CLASS_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSHTB_CLASS_PARMS]); |
| + |
| + fprintf(f, "burst %s ", sprint_size(qopt->burst, b1)); |
| + fprintf(f, "rate %s ", sprint_rate(qopt->rate, b1)); |
| + fprintf(f, "cburst %s ", sprint_size(qopt->cburst, b1)); |
| + fprintf(f, "crate %s ", sprint_rate(qopt->crate, b1)); |
| + fprintf(f, "priority %u ", qopt->priority); |
| + fprintf(f, "quantum %s ", sprint_size(qopt->quantum, b1)); |
| + fprintf(f, "overhead %s ", sprint_size(qopt->overhead, b1)); |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nsshtb_qdisc_util = { |
| + .id = "nsshtb", |
| + .parse_qopt = nsshtb_parse_opt, |
| + .print_qopt = nsshtb_print_opt, |
| + .parse_copt = nsshtb_parse_class_opt, |
| + .print_copt = nsshtb_print_class_opt, |
| +}; |
| + |
| +/* ======================== NSSBLACKHOLE ======================= */ |
| + |
| +static void nssblackhole_explain(void) |
| +{ |
| + fprintf(stderr, "Usage: ... nssblackhole [ set_default ]\n"); |
| +} |
| + |
| +static int nssblackhole_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) |
| +{ |
| + struct rtattr *tail; |
| + struct tc_nssblackhole_qopt opt; |
| + |
| + memset(&opt, 0, sizeof(opt)); |
| + |
| + while (argc > 0) { |
| + if (strcmp(*argv, "set_default") == 0) { |
| + opt.set_default = 1; |
| + } else if (strcmp(*argv, "help") == 0) { |
| + nssblackhole_explain(); |
| + return -1; |
| + } else { |
| + fprintf(stderr, "What is \"%s\"?\n", *argv); |
| + nssblackhole_explain(); |
| + return -1; |
| + } |
| + argc--; argv++; |
| + } |
| + |
| + tail = NLMSG_TAIL(n); |
| + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); |
| + addattr_l(n, 1024, TCA_NSSBLACKHOLE_PARMS, &opt, sizeof(opt)); |
| + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
| + return 0; |
| +} |
| + |
| +static int nssblackhole_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| +{ |
| + struct rtattr *tb[TCA_NSSBLACKHOLE_MAX + 1]; |
| + struct tc_nssblackhole_qopt *qopt; |
| + SPRINT_BUF(b1); |
| + |
| + if (opt == NULL) |
| + return 0; |
| + |
| + parse_rtattr_nested(tb, TCA_NSSBLACKHOLE_MAX, opt); |
| + |
| + if (tb[TCA_NSSBLACKHOLE_PARMS] == NULL) |
| + return -1; |
| + |
| + if (RTA_PAYLOAD(tb[TCA_NSSBLACKHOLE_PARMS]) < sizeof(*qopt)) |
| + return -1; |
| + |
| + qopt = RTA_DATA(tb[TCA_NSSBLACKHOLE_PARMS]); |
| + |
| + if (qopt->set_default) |
| + fprintf(f, "set_default "); |
| + |
| + return 0; |
| +} |
| + |
| +struct qdisc_util nssblackhole_qdisc_util = { |
| + .id = "nssblackhole", |
| + .parse_qopt = nssblackhole_parse_opt, |
| + .print_qopt = nssblackhole_print_opt, |
| +}; |
| -- |
| 2.21.0 |
| |