diff --git a/iproute2/Makefile b/iproute2/Makefile index 4eaaf28a0..1405f0752 100644 --- a/iproute2/Makefile +++ b/iproute2/Makefile @@ -236,7 +236,7 @@ $(eval $(call BuildPackage,ip-full)) # build tc-mod-iptables before its dependents, to avoid # spurious rebuilds when building multiple variants. $(eval $(call BuildPackage,tc-mod-iptables)) -$(eval $(call BuildPackage,tc-tiny)) +#$(eval $(call BuildPackage,tc-tiny)) $(eval $(call BuildPackage,tc-full)) $(eval $(call BuildPackage,genl)) $(eval $(call BuildPackage,ip-bridge)) diff --git a/iproute2/patches/400-add-nss-qdisc.patch b/iproute2/patches/400-add-nss-qdisc.patch deleted file mode 100644 index b6e969bd0..000000000 --- a/iproute2/patches/400-add-nss-qdisc.patch +++ /dev/null @@ -1,2094 +0,0 @@ ---- a/include/uapi/linux/pkt_sched.h -+++ b/include/uapi/linux/pkt_sched.h -@@ -119,6 +119,251 @@ enum { - - #define TCA_STAB_MAX (__TCA_STAB_MAX - 1) - -+enum { -+ TCA_NSS_ACCEL_MODE_NSS_FW, -+ TCA_NSS_ACCEL_MODE_PPE, -+ TCA_NSS_ACCEL_MODE_MAX -+}; -+ -+/* 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 */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* 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: pkts are all enqueued */ -+ __u32 max; /* qlen_avg > max: pkts are all 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 */ -+ enum tc_nsswred_weight_modes 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: DP */ -+ __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 */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* 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; /* Max number of packets that can be held in the queue */ -+ __u32 interval; /* Monitoring interval */ -+ __u32 flows; /* Number of flow buckets */ -+ __u32 quantum; /* Weight (in bytes) used for DRR of flow buckets */ -+ __u8 ecn; /* 0 - disable ECN, 1 - enable ECN */ -+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+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 */ -+}; -+ -+/* NSSFQ_CODEL section */ -+ -+struct tc_nssfq_codel_xstats { -+ __u32 new_flow_count; /* Total number of new flows seen */ -+ __u32 new_flows_len; /* Current number of new flows */ -+ __u32 old_flows_len; /* Current number of old flows */ -+ __u32 ecn_mark; /* Number of packets marked with ECN */ -+ __u32 drop_overlimit; /* Number of packets dropped due to overlimit */ -+ __u32 maxpacket; /* The largest packet seen so far in the queue */ -+}; -+ -+/* 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 */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* 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 { -+ __u32 bands; /* Number of bands */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* 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; /* Quantum allocation for DRR */ -+}; -+ -+struct tc_nssbf_qopt { -+ __u16 defcls; /* Default class value */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSWRR section */ -+ -+enum { -+ TCA_NSSWRR_UNSPEC, -+ TCA_NSSWRR_CLASS_PARMS, -+ TCA_NSSWRR_QDISC_PARMS, -+ __TCA_NSSWRR_MAX -+}; -+ -+#define TCA_NSSWRR_MAX (__TCA_NSSWRR_MAX - 1) -+ -+struct tc_nsswrr_class_qopt { -+ __u32 quantum; /* Weight associated to this class */ -+}; -+ -+struct tc_nsswrr_qopt { -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSWFQ section */ -+ -+enum { -+ TCA_NSSWFQ_UNSPEC, -+ TCA_NSSWFQ_CLASS_PARMS, -+ TCA_NSSWFQ_QDISC_PARMS, -+ __TCA_NSSWFQ_MAX -+}; -+ -+#define TCA_NSSWFQ_MAX (__TCA_NSSWFQ_MAX - 1) -+ -+struct tc_nsswfq_class_qopt { -+ __u32 quantum; /* Weight associated to this class */ -+}; -+ -+struct tc_nsswfq_qopt { -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* 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 */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* 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 */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+ - /* FIFO section */ - - struct tc_fifo_qopt { ---- a/tc/Makefile -+++ b/tc/Makefile -@@ -82,6 +82,7 @@ TCMODULES += q_etf.o - TCMODULES += q_taprio.o - TCMODULES += q_plug.o - TCMODULES += q_ets.o -+TCMODULES += q_nss.o - - TCSO := - ifeq ($(TC_CONFIG_ATM),y) ---- /dev/null -+++ b/tc/q_nss.c -@@ -0,0 +1,1826 @@ -+/* -+ ************************************************************************** -+ * Copyright (c) 2015, 2018 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 ] [ accel_mode ]\n"); -+} -+ -+static void nsswred_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nsswred setup DPs NUMBER dp_default NUMBER [ weight_mode dscp ] [ecn] [ set_default ] [ accel_mode ]\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; -+ bool accel_mode = false; -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "DPs") == 0) { -+ NEXT_ARG(); -+ if (get_unsigned(&dps, *argv, 0) || dps > NSSWRED_CLASS_MAX) { -+ -+ fprintf(stderr, "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, "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 if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nsswred_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_NSS_FW; -+ } else if (opt.accel_mode != TCA_NSS_ACCEL_MODE_NSS_FW) { -+ fprintf(stderr, "accel_mode should be %d\n", TCA_NSS_ACCEL_MODE_NSS_FW); -+ return -1; -+ } -+ -+ if (!dps || !def_dp) { -+ fprintf(stderr, "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); -+ bool accel_mode = false; -+ -+ 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, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } 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 (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "Accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ if (weighted) { -+ if (!opt.limit || !opt.rap.min || !opt.rap.max || !opt.traffic_id || !avpkt || !opt.weight_mode_value) { -+ fprintf(stderr, "Require limit, min, max, avpkt, DP, weight_mode_value\n"); -+ return -1; -+ } -+ } else { -+ if (!opt.limit || !avpkt) { -+ fprintf(stderr, "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, "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 "); -+ -+ fprintf(f, "accel_mode: %d ", qopt->accel_mode); -+ -+ 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 ] [ accel_mode ]\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; -+ bool accel_mode = false; -+ -+ 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, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nssfifo_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nssfifo_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ 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 "); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ 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, -+}; -+ -+/* ======================== NSSFQ_CODEL =======================*/ -+ -+static void nssfq_codel_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nssfq_codel target TIME interval TIME [ flows NUMBER ] [ quantum BYTES ]" -+ "[ limit PACKETS ] [ set_default ] [ accel_mode ]\n"); -+} -+ -+static void nssfq_codel_explain_err1(void) -+{ -+ fprintf(stderr, "Value of target and interval should be greater than 1ms\n"); -+} -+ -+static int nssfq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) -+{ -+ struct rtattr *tail; -+ struct tc_nsscodel_qopt opt; -+ bool accel_mode = false; -+ -+ 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, "flows") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.flows, *argv) || opt.flows == 0) { -+ fprintf(stderr, "Illegal \"flows\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "quantum") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.quantum, *argv) || opt.quantum == 0) { -+ fprintf(stderr, "Illegal \"quantum\"\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, "ecn") == 0) { -+ fprintf(stderr, "Illegal, ECN not supported\n"); -+ nssfq_codel_explain(); -+ return -1; -+ } else if (strcmp(*argv, "set_default") == 0) { -+ opt.set_default = 1; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nssfq_codel_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nssfq_codel_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_NSS_FW; -+ } else if (opt.accel_mode != TCA_NSS_ACCEL_MODE_NSS_FW) { -+ fprintf(stderr, "accel_mode should be %d\n", TCA_NSS_ACCEL_MODE_NSS_FW); -+ return -1; -+ } -+ -+ if (!opt.target || !opt.interval) { -+ nssfq_codel_explain(); -+ return -1; -+ } -+ -+ if (opt.target < 1000 || opt.interval < 1000) { -+ nssfq_codel_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 nssfq_codel_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 flows %u quantum %u ", -+ sprint_time(qopt->target, b1), -+ qopt->limit, -+ sprint_time(qopt->interval, b2), -+ qopt->flows, -+ qopt->quantum); -+ -+ if (qopt->ecn) -+ fprintf(f, "ecn "); -+ -+ if (qopt->set_default) -+ fprintf(f, "set_default "); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+static int nssfq_codel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) -+{ -+ struct tc_nssfq_codel_xstats *st; -+ -+ if (xstats == NULL) -+ return 0; -+ -+ if (RTA_PAYLOAD(xstats) < sizeof(*st)) -+ return -1; -+ -+ st = RTA_DATA(xstats); -+ fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u ecn_mark %u\n", -+ st->maxpacket, st->drop_overlimit, st->new_flow_count, st->ecn_mark); -+ fprintf(f, " new_flows_len %u old_flows_len %u", st->new_flows_len, st->old_flows_len); -+ -+ return 0; -+} -+ -+struct qdisc_util nssfq_codel_qdisc_util = { -+ .id = "nssfq_codel", -+ .parse_qopt = nssfq_codel_parse_opt, -+ .print_qopt = nssfq_codel_print_opt, -+ .print_xstats = nssfq_codel_print_xstats, -+}; -+ -+/* ======================== NSSCODEL =======================*/ -+ -+static void nsscodel_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nsscodel target TIME interval TIME [ limit PACKETS ] [ set_default ] [ accel_mode ]\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; -+ bool accel_mode = false; -+ -+ 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, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } 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 (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_NSS_FW; -+ } else if (opt.accel_mode != TCA_NSS_ACCEL_MODE_NSS_FW) { -+ fprintf(stderr, "accel_mode should be %d\n", TCA_NSS_ACCEL_MODE_NSS_FW); -+ return -1; -+ } -+ -+ 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 "); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ 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 ] [ accel_mode ]\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; -+ bool accel_mode = false; -+ -+ 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, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } 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 (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ if (!opt.rate || !opt.burst) { -+ fprintf(stderr, "Both \"rate\" and \"burst\" are required.\n"); -+ return -1; -+ } -+ -+ /* -+ * Peakrate is currently not supported, but we keep the infrastructure -+ * for future use. However, we have disabled taking input for this. -+ */ -+ 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; -+ -+ 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]); -+ -+ print_size(PRINT_FP, NULL, "buffer/maxburst %s ", qopt->burst); -+ tc_print_rate(PRINT_FP, NULL, "rate %s ", qopt->rate); -+ print_size(PRINT_FP, NULL, "mtu %s ", qopt->mtu); -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ 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) ] [ accel_mode ]\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; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "bands") == 0) { -+ NEXT_ARG(); -+ if (get_unsigned(&opt.bands, *argv, 0)) { -+ fprintf(stderr, "Illegal \"limit\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } 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; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ 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); -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ 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 [ accel_mode ]\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; -+ bool accel_mode = false; -+ -+ 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 (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } 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++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_NSS_FW; -+ } else if (opt.accel_mode != TCA_NSS_ACCEL_MODE_NSS_FW) { -+ fprintf(stderr, "accel_mode should be %d\n", TCA_NSS_ACCEL_MODE_NSS_FW); -+ return -1; -+ } -+ -+ 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 rtattr *tb[TCA_NSSBF_MAX + 1]; -+ struct tc_nssbf_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSBF_MAX, opt); -+ -+ if (tb[TCA_NSSBF_QDISC_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSBF_QDISC_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSBF_QDISC_PARMS]); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ 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; -+ -+ 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]); -+ -+ print_size(PRINT_FP, NULL, "burst %s ", qopt->burst); -+ tc_print_rate(PRINT_FP, NULL, "rate %s ", qopt->rate); -+ print_size(PRINT_FP, NULL, "quantum %s ", qopt->quantum); -+ print_size(PRINT_FP, NULL, "mtu %s ", qopt->mtu); -+ -+ 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 [ accel_mode ]\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) -+{ -+ struct tc_nsswrr_qopt opt; -+ bool accel_mode = false; -+ struct rtattr *tail; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (matches(*argv, "help") == 0) { -+ nsswrr_explain_qdisc(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\" ?\n", *argv); -+ nsswrr_explain_qdisc(); -+ return -1; -+ } -+ argc--, argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSWRR_QDISC_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsswrr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSWRR_MAX + 1]; -+ struct tc_nsswrr_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSWRR_MAX, opt); -+ -+ if (tb[TCA_NSSWRR_QDISC_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSWRR_QDISC_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSWRR_QDISC_PARMS]); -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ 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 [ accel_mode ]\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) -+{ -+ struct tc_nsswfq_qopt opt; -+ bool accel_mode = false; -+ struct rtattr *tail; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else 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++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSWFQ_QDISC_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsswfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSWFQ_MAX + 1]; -+ struct tc_nsswfq_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSWFQ_MAX, opt); -+ -+ if (tb[TCA_NSSWFQ_QDISC_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSWFQ_QDISC_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSWFQ_QDISC_PARMS]); -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ 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_size(&opt.quantum, *argv)) { -+ 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 ] [ accel_mode ]\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; -+ bool accel_mode = false; -+ -+ 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, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } 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++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ 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 rtattr *tb[TCA_NSSHTB_MAX + 1]; -+ struct tc_nsshtb_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSHTB_MAX, opt); -+ -+ if (tb[TCA_NSSHTB_QDISC_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSHTB_QDISC_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSHTB_QDISC_PARMS]); -+ -+ if (qopt->r2q != 0) -+ fprintf(f, "r2q %u ", qopt->r2q); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ 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]); -+ -+ print_size(PRINT_FP, NULL, "burst %s ", qopt->burst); -+ tc_print_rate(PRINT_FP, NULL, "rate %s ", qopt->rate); -+ print_size(PRINT_FP, NULL, "cburst %s ", qopt->cburst); -+ tc_print_rate(PRINT_FP, NULL, "crate %s ", qopt->crate); -+ fprintf(f, "priority %u ", qopt->priority); -+ print_size(PRINT_FP, NULL, "quantum %s ", qopt->quantum); -+ print_size(PRINT_FP, NULL, "overhead %s ", qopt->overhead); -+ -+ 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 ] [ accel_mode ]\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; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "set_default") == 0) { -+ opt.set_default = 1; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nssblackhole_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nssblackhole_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ 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; -+ -+ 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 "); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+struct qdisc_util nssblackhole_qdisc_util = { -+ .id = "nssblackhole", -+ .parse_qopt = nssblackhole_parse_opt, -+ .print_qopt = nssblackhole_print_opt, -+}; - diff --git a/iproute2/patches/500-add-nssmirred.patch b/iproute2/patches/500-add-nssmirred.patch deleted file mode 100644 index e48058e6c..000000000 --- a/iproute2/patches/500-add-nssmirred.patch +++ /dev/null @@ -1,243 +0,0 @@ ---- a/tc/Makefile 2019-04-08 12:48:15.425854828 +0530 -+++ b/tc/Makefile 2019-04-08 13:03:17.204741000 +0530 -@@ -54,6 +54,7 @@ TCMODULES += m_bpf.o - TCMODULES += m_sample.o - TCMODULES += m_ct.o - TCMODULES += m_gate.o -+TCMODULES += m_nssmirred.o - TCMODULES += p_ip.o - TCMODULES += p_ip6.o - TCMODULES += p_icmp.o ---- /dev/null 1970-01-01 05:30:00.000000000 +0530 -+++ b/tc/m_nssmirred.c 2019-06-19 14:25:51.369793000 +0530 -@@ -0,0 +1,183 @@ -+/* -+ ************************************************************************** -+ * Copyright (c) 2019 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include "utils.h" -+#include "tc_util.h" -+#include "tc_common.h" -+#include -+ -+/* -+ * explain() -+ * API to print the explaination of nssmirred action statement's -+ * elements. -+ */ -+static void explain(void) -+{ -+ fprintf(stderr, "Usage: nssmirred redirect \n"); -+ fprintf(stderr, "where: \n"); -+ fprintf(stderr, "\tTO_DEVICENAME is the devicename to redirect to\n"); -+ fprintf(stderr, "\tFROM_DEVICENAME is the devicename to redirect from\n"); -+} -+ -+/* -+ * usage() -+ * API to show the usage of the nssmirred action. -+ */ -+static void usage(void) -+{ -+ explain(); -+ exit(-1); -+} -+ -+/* -+ * parse_nss_mirred() -+ * Parse and validate the nssmirred action statement. -+ */ -+static int parse_nss_mirred(struct action_util *a, int *argc_p, char ***argv_p, -+ int tca_id, struct nlmsghdr *n) -+{ -+ int idx, argc = *argc_p; -+ char **argv = *argv_p; -+ struct tc_nss_mirred p; -+ struct rtattr *tail; -+ -+ if (argc < 0) { -+ fprintf(stderr, "nssmirred bad argument count %d. Try option \"help\"\n", argc); -+ goto error; -+ } -+ -+ if (matches(*argv, "nssmirred")) { -+ fprintf(stderr, "nssmirred bad argument %s. Try option \"help\"\n", *argv); -+ goto error; -+ } -+ -+ NEXT_ARG(); -+ if (!matches(*argv, "help")) { -+ usage(); -+ } -+ -+ if (matches(*argv, "redirect")) { -+ fprintf(stderr, "nssmirred bad argument %s. Try option \"help\"\n", *argv); -+ goto error; -+ } -+ -+ NEXT_ARG(); -+ if (matches(*argv, "dev")) { -+ fprintf(stderr, "nssmirred: bad value %s. Try option \"help\"\n", *argv); -+ goto error; -+ } -+ -+ NEXT_ARG(); -+ memset(&p, 0, sizeof(struct tc_nss_mirred)); -+ if ((idx = ll_name_to_index(*argv)) == 0) { -+ fprintf(stderr, "Cannot find to device \"%s\"\n", *argv); -+ goto error; -+ } -+ -+ p.to_ifindex = idx; -+ NEXT_ARG(); -+ if (matches(*argv, "fromdev")) { -+ fprintf(stderr, "nssmirred: bad value %s. Try option \"help\"\n", *argv); -+ goto error; -+ } -+ -+ NEXT_ARG(); -+ if ((idx = ll_name_to_index(*argv)) == 0) { -+ fprintf(stderr, "Cannot find from device \"%s\"\n", *argv); -+ goto error; -+ } -+ -+ p.from_ifindex = idx; -+ p.action = TC_ACT_STOLEN; -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, MAX_MSG, tca_id, NULL, 0); -+ addattr_l(n, MAX_MSG, TCA_NSS_MIRRED_PARMS, &p, sizeof (p)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ argc--; -+ argv++; -+ *argc_p = argc; -+ *argv_p = argv; -+ return 0; -+ -+error: -+ return -1; -+} -+ -+/* -+ * print_nss_mirred() -+ * Print information related to nssmirred action. -+ */ -+static int print_nss_mirred(struct action_util *au, FILE * f, struct rtattr *arg) -+{ -+ struct tc_nss_mirred *p; -+ struct rtattr *tb[TCA_NSS_MIRRED_MAX + 1]; -+ const char *from_dev, *to_dev; -+ -+ if (arg == NULL) { -+ return -1; -+ } -+ -+ parse_rtattr_nested(tb, TCA_NSS_MIRRED_MAX, arg); -+ -+ if (tb[TCA_NSS_MIRRED_PARMS] == NULL) { -+ fprintf(f, "[NULL nssmirred parameters]"); -+ goto error; -+ } -+ -+ p = RTA_DATA(tb[TCA_NSS_MIRRED_PARMS]); -+ if ((from_dev = ll_index_to_name(p->from_ifindex)) == 0) { -+ fprintf(stderr, "Invalid interface (index: %d)\n", p->from_ifindex); -+ goto error; -+ } -+ -+ if ((to_dev = ll_index_to_name(p->to_ifindex)) == 0) { -+ fprintf(stderr, "Invalid interface (index: %d)\n", p->to_ifindex); -+ goto error; -+ } -+ -+ fprintf(f, "nssmirred (%s to device %s) stolen\n", from_dev, to_dev); -+ fprintf(f, "\tindex %d ref %d bind %d\n",p->index,p->refcnt,p->bindcnt); -+ -+ if (show_stats) { -+ if (tb[TCA_NSS_MIRRED_TM]) { -+ struct tcf_t *tm = RTA_DATA(tb[TCA_NSS_MIRRED_TM]); -+ print_tm(f,tm); -+ } -+ } -+ return 0; -+ -+error: -+ return -1; -+} -+ -+/* -+ * nssmirred_action_util -+ * nssmirred action utility structure. -+ */ -+struct action_util nssmirred_action_util = { -+ .id = "nssmirred", -+ .parse_aopt = parse_nss_mirred, -+ .print_aopt = print_nss_mirred, -+}; ---- /dev/null 1970-01-01 05:30:00.000000000 +0530 -+++ a/include/linux/tc_act/tc_nssmirred.h 2019-06-19 14:25:40.787768000 +0530 -@@ -0,0 +1,44 @@ -+/* -+ ************************************************************************** -+ * Copyright (c) 2019 The Linux Foundation. All rights reserved. -+ * Permission to use, copy, modify, and/or distribute this software for -+ * any purpose with or without fee is hereby granted, provided that the -+ * above copyright notice and this permission notice appear in all copies. -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ ************************************************************************** -+ */ -+ -+#ifndef __LINUX_TC_NSS_MIR_H -+#define __LINUX_TC_NSS_MIR_H -+ -+#include -+#include -+ -+/* -+ * tc_nss_mirred -+ * Structure for nssmirred action. -+ */ -+struct tc_nss_mirred { -+ tc_gen; -+ __u32 from_ifindex; /* ifindex of the port to be redirected from */ -+ __u32 to_ifindex; /* ifindex of the port to be redirected to */ -+}; -+ -+/* -+ * Types of nssmirred action parameters. -+ */ -+enum { -+ TCA_NSS_MIRRED_UNSPEC, -+ TCA_NSS_MIRRED_TM, -+ TCA_NSS_MIRRED_PARMS, -+ __TCA_NSS_MIRRED_MAX -+}; -+#define TCA_NSS_MIRRED_MAX (__TCA_NSS_MIRRED_MAX - 1) -+ -+#endif /* __LINUX_TC_NSS_MIR_H */