[Cake] [PATCH iproute2-next v10] Add support for CAKE qdisc
David Ahern
dsahern at gmail.com
Tue Jul 17 22:31:43 EDT 2018
On 7/16/18 10:39 AM, Toke Høiland-Jørgensen wrote:
> +static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
> + struct nlmsghdr *n, const char *dev)
> +{
> + int unlimited = 0;
> + __u64 bandwidth = 0;
> + unsigned interval = 0;
> + unsigned target = 0;
> + unsigned diffserv = 0;
> + unsigned memlimit = 0;
> + int overhead = 0;
> + bool overhead_set = false;
> + bool overhead_override = false;
> + int mpu = 0;
> + int flowmode = -1;
> + int nat = -1;
> + int atm = -1;
> + int autorate = -1;
> + int wash = -1;
> + int ingress = -1;
> + int ack_filter = -1;
> + struct rtattr *tail;
> + struct cake_preset *preset, *preset_set = NULL;
For consistency, please use reverse xmas tree like the net code.
> +
> + while (argc > 0) {
> + if (strcmp(*argv, "bandwidth") == 0) {
> + NEXT_ARG();
> + if (get_rate64(&bandwidth, *argv)) {
> + fprintf(stderr, "Illegal \"bandwidth\"\n");
> + return -1;
> + }
> + unlimited = 0;
> + autorate = 0;
> + } else if (strcmp(*argv, "unlimited") == 0) {
> + bandwidth = 0;
> + unlimited = 1;
> + autorate = 0;
> + } else if (strcmp(*argv, "autorate_ingress") == 0) {
> + autorate = 1;
> +
for consistency, drop the extra newline.
> + } else if (strcmp(*argv, "rtt") == 0) {
> + NEXT_ARG();
> + if (get_time(&interval, *argv)) {
> + fprintf(stderr, "Illegal \"rtt\"\n");
> + return -1;
> + }
> + target = interval / 20;
> + if(!target)
space between 'if('
> + target = 1;
> + } else if ((preset = find_preset(*argv))) {
> + if (preset_set)
> + duparg(*argv, preset_set->name);
> + preset_set = preset;
> + target = preset->target;
> + interval = preset->interval;
> +
extra newline here and many more below. Be consistent with the option list.
> + } else if (strcmp(*argv, "besteffort") == 0) {
> + diffserv = CAKE_DIFFSERV_BESTEFFORT;
> + } else if (strcmp(*argv, "precedence") == 0) {
> + diffserv = CAKE_DIFFSERV_PRECEDENCE;
> + } else if (strcmp(*argv, "diffserv8") == 0) {
> + diffserv = CAKE_DIFFSERV_DIFFSERV8;
> + } else if (strcmp(*argv, "diffserv4") == 0) {
> + diffserv = CAKE_DIFFSERV_DIFFSERV4;
> + } else if (strcmp(*argv, "diffserv") == 0) {
> + diffserv = CAKE_DIFFSERV_DIFFSERV4;
> + } else if (strcmp(*argv, "diffserv3") == 0) {
> + diffserv = CAKE_DIFFSERV_DIFFSERV3;
> +
> + } else if (strcmp(*argv, "nowash") == 0) {
> + wash = 0;
...
> +
> + tail = NLMSG_TAIL(n);
> + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
> + if (bandwidth || unlimited)
> + addattr_l(n, 1024, TCA_CAKE_BASE_RATE64, &bandwidth, sizeof(bandwidth));
> + if (diffserv)
> + addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(diffserv));
> + if (atm != -1)
> + addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm));
> + if (flowmode != -1)
> + addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowmode));
> + if (overhead_set)
> + addattr_l(n, 1024, TCA_CAKE_OVERHEAD, &overhead, sizeof(overhead));
> + if (overhead_override) {
> + unsigned zero = 0;
> + addattr_l(n, 1024, TCA_CAKE_RAW, &zero, sizeof(zero));
> + }
> + if (mpu > 0)
> + addattr_l(n, 1024, TCA_CAKE_MPU, &mpu, sizeof(mpu));
> + if (interval)
> + addattr_l(n, 1024, TCA_CAKE_RTT, &interval, sizeof(interval));
> + if (target)
> + addattr_l(n, 1024, TCA_CAKE_TARGET, &target, sizeof(target));
> + if (autorate != -1)
> + addattr_l(n, 1024, TCA_CAKE_AUTORATE, &autorate, sizeof(autorate));
> + if (memlimit)
> + addattr_l(n, 1024, TCA_CAKE_MEMORY, &memlimit, sizeof(memlimit));
> + if (nat != -1)
> + addattr_l(n, 1024, TCA_CAKE_NAT, &nat, sizeof(nat));
> + if (wash != -1)
> + addattr_l(n, 1024, TCA_CAKE_WASH, &wash, sizeof(wash));
> + if (ingress != -1)
> + addattr_l(n, 1024, TCA_CAKE_INGRESS, &ingress, sizeof(ingress));
> + if (ack_filter != -1)
> + addattr_l(n, 1024, TCA_CAKE_ACK_FILTER, &ack_filter, sizeof(ack_filter));
there are a number of lines > 80 columns as well. violating for user
messages is fine, but the above needs to be wrapped.
> +
> + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
> + return 0;
> +}
> +
> +
extra newline
> +static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
> +{
> + struct rtattr *tb[TCA_CAKE_MAX + 1];
> + __u64 bandwidth = 0;
> + unsigned diffserv = 0;
> + unsigned flowmode = 0;
> + unsigned interval = 0;
> + unsigned memlimit = 0;
> + int overhead = 0;
> + int raw = 0;
> + int mpu = 0;
> + int atm = 0;
> + int nat = 0;
> + int autorate = 0;
> + int wash = 0;
> + int ingress = 0;
> + int ack_filter = 0;
> + int split_gso = 0;
> + SPRINT_BUF(b1);
> + SPRINT_BUF(b2);
> +
> + if (opt == NULL)
> + return 0;
> +
> + parse_rtattr_nested(tb, TCA_CAKE_MAX, opt);
> +
> + if (tb[TCA_CAKE_BASE_RATE64] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE64]) >= sizeof(bandwidth)) {
> + bandwidth = rta_getattr_u64(tb[TCA_CAKE_BASE_RATE64]);
> + if(bandwidth) {
space between 'if('. There a number of these throughout the file. please
fix them all. I have git am configured to run checkpatch; it tells you
what needs to be fixed.
> + print_uint(PRINT_JSON, "bandwidth", NULL, bandwidth);
> + print_string(PRINT_FP, NULL, "bandwidth %s ", sprint_rate(bandwidth, b1));
> + } else
> + print_string(PRINT_ANY, "bandwidth", "bandwidth %s ", "unlimited");
> + }
> + if (tb[TCA_CAKE_AUTORATE] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_AUTORATE]) >= sizeof(__u32)) {
> + autorate = rta_getattr_u32(tb[TCA_CAKE_AUTORATE]);
> + if(autorate == 1)
> + print_string(PRINT_ANY, "autorate", "autorate_%s ", "ingress");
> + else if(autorate)
> + print_string(PRINT_ANY, "autorate", "(?autorate?) ", "unknown");
Why the '(?' and '?)'? here and the diffserv below.
> + }
> + if (tb[TCA_CAKE_DIFFSERV_MODE] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >= sizeof(__u32)) {
> + diffserv = rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]);
> + switch(diffserv) {
> + case CAKE_DIFFSERV_DIFFSERV3:
> + print_string(PRINT_ANY, "diffserv", "%s ", "diffserv3");
> + break;
> + case CAKE_DIFFSERV_DIFFSERV4:
> + print_string(PRINT_ANY, "diffserv", "%s ", "diffserv4");
> + break;
> + case CAKE_DIFFSERV_DIFFSERV8:
> + print_string(PRINT_ANY, "diffserv", "%s ", "diffserv8");
> + break;
> + case CAKE_DIFFSERV_BESTEFFORT:
> + print_string(PRINT_ANY, "diffserv", "%s ", "besteffort");
> + break;
> + case CAKE_DIFFSERV_PRECEDENCE:
> + print_string(PRINT_ANY, "diffserv", "%s ", "precedence");
> + break;
> + default:
> + print_string(PRINT_ANY, "diffserv", "(?diffserv?) ", "unknown");
> + break;
> + };
The diffserv and flowmode below could both be simplified using a helper,
e.g., cake_print_diffsev, and an array of strings indexed by the value.
> + }
> + if (tb[TCA_CAKE_FLOW_MODE] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >= sizeof(__u32)) {
> + flowmode = rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]);
> + switch(flowmode) {
> + case CAKE_FLOW_NONE:
> + print_string(PRINT_ANY, "flowmode", "%s ", "flowblind");
> + break;
> + case CAKE_FLOW_SRC_IP:
> + print_string(PRINT_ANY, "flowmode", "%s ", "srchost");
> + break;
> + case CAKE_FLOW_DST_IP:
> + print_string(PRINT_ANY, "flowmode", "%s ", "dsthost");
> + break;
> + case CAKE_FLOW_HOSTS:
> + print_string(PRINT_ANY, "flowmode", "%s ", "hosts");
> + break;
> + case CAKE_FLOW_FLOWS:
> + print_string(PRINT_ANY, "flowmode", "%s ", "flows");
> + break;
> + case CAKE_FLOW_DUAL_SRC:
> + print_string(PRINT_ANY, "flowmode", "%s ", "dual-srchost");
> + break;
> + case CAKE_FLOW_DUAL_DST:
> + print_string(PRINT_ANY, "flowmode", "%s ", "dual-dsthost");
> + break;
> + case CAKE_FLOW_TRIPLE:
> + print_string(PRINT_ANY, "flowmode", "%s ", "triple-isolate");
> + break;
> + default:
> + print_string(PRINT_ANY, "flowmode", "(?flowmode?) ", "unknown");
> + break;
> + };
> +
extra newline. check the whole file for these.
> + }
> +
> + if (tb[TCA_CAKE_NAT] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_NAT]) >= sizeof(__u32)) {
> + nat = rta_getattr_u32(tb[TCA_CAKE_NAT]);
> + }
> +
> + if(nat)
> + print_string(PRINT_FP, NULL, "nat ", NULL);
> + print_bool(PRINT_JSON, "nat", NULL, nat);
why is the fp print under the if check but the json one is not? you have
this in a number of places. Why not be consistent in the output?
> +
> + if (tb[TCA_CAKE_WASH] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_WASH]) >= sizeof(__u32)) {
> + wash = rta_getattr_u32(tb[TCA_CAKE_WASH]);
> + }
> + if (tb[TCA_CAKE_ATM] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >= sizeof(__u32)) {
> + atm = rta_getattr_u32(tb[TCA_CAKE_ATM]);
> + }
> + if (tb[TCA_CAKE_OVERHEAD] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_OVERHEAD]) >= sizeof(__s32)) {
> + overhead = *(__s32 *) RTA_DATA(tb[TCA_CAKE_OVERHEAD]);
> + }
> + if (tb[TCA_CAKE_MPU] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_MPU]) >= sizeof(__u32)) {
> + mpu = rta_getattr_u32(tb[TCA_CAKE_MPU]);
> + }
> + if (tb[TCA_CAKE_INGRESS] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_INGRESS]) >= sizeof(__u32)) {
> + ingress = rta_getattr_u32(tb[TCA_CAKE_INGRESS]);
> + }
> + if (tb[TCA_CAKE_ACK_FILTER] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_ACK_FILTER]) >= sizeof(__u32)) {
> + ack_filter = rta_getattr_u32(tb[TCA_CAKE_ACK_FILTER]);
> + }
> + if (tb[TCA_CAKE_SPLIT_GSO] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_SPLIT_GSO]) >= sizeof(__u32)) {
> + split_gso = rta_getattr_u32(tb[TCA_CAKE_SPLIT_GSO]);
> + }
> + if (tb[TCA_CAKE_RAW]) {
> + raw = 1;
> + }
It would be better to kee this with its use below.
> + if (tb[TCA_CAKE_RTT] &&
> + RTA_PAYLOAD(tb[TCA_CAKE_RTT]) >= sizeof(__u32)) {
> + interval = rta_getattr_u32(tb[TCA_CAKE_RTT]);
> + }
> +
> + if (wash)
> + print_string(PRINT_FP, NULL, "wash ", NULL);
> + print_bool(PRINT_JSON, "wash", NULL, wash);
> +
> + if (ingress)
> + print_string(PRINT_FP, NULL, "ingress ", NULL);
> + print_bool(PRINT_JSON, "ingress", NULL, ingress);
> +
> + if (ack_filter == CAKE_ACK_AGGRESSIVE)
> + print_string(PRINT_ANY, "ack-filter", "ack-filter-%s ", "aggressive");
> + else if (ack_filter == CAKE_ACK_FILTER)
> + print_string(PRINT_ANY, "ack-filter", "ack-filter ", "enabled");
> + else
> + print_string(PRINT_JSON, "ack-filter", NULL, "disabled");
> +
> + if (split_gso)
> + print_string(PRINT_FP, NULL, "split-gso ", NULL);
> + print_bool(PRINT_JSON, "split_gso", NULL, split_gso);
> +
> + if (interval)
> + print_string(PRINT_FP, NULL, "rtt %s ", sprint_time(interval, b2));
> + print_uint(PRINT_JSON, "rtt", NULL, interval);
> +
> + if (raw)
> + print_string(PRINT_FP, NULL, "raw ", NULL);
> + print_bool(PRINT_JSON, "raw", NULL, raw);
> +
> + if (atm == CAKE_ATM_ATM)
> + print_string(PRINT_ANY, "atm", "%s ", "atm");
> + else if (atm == CAKE_ATM_PTM)
> + print_string(PRINT_ANY, "atm", "%s ", "ptm");
> + else if (!raw)
> + print_string(PRINT_ANY, "atm", "%s ", "noatm");
> +
> + print_int(PRINT_ANY, "overhead", "overhead %d ", overhead);
> +
> + if (mpu)
> + print_uint(PRINT_ANY, "mpu", "mpu %u ", mpu);
> +
> + if (memlimit) {
> + print_uint(PRINT_JSON, "memlimit", NULL, memlimit);
> + print_string(PRINT_FP, NULL, "memlimit %s", sprint_size(memlimit, b1));
> + }
> +
> + return 0;
> +}
> +
> +static void cake_print_json_tin(struct rtattr **tstat)
> +{
> +#define PRINT_TSTAT_JSON(type, name, attr) if (tstat[TCA_CAKE_TIN_STATS_ ## attr]) \
> + print_u64(PRINT_JSON, name, NULL, \
> + rta_getattr_ ## type((struct rtattr *)tstat[TCA_CAKE_TIN_STATS_ ## attr]))
> +
> + open_json_object(NULL);
> + PRINT_TSTAT_JSON(u64, "threshold_rate", THRESHOLD_RATE64);
> + PRINT_TSTAT_JSON(u64, "sent_bytes", SENT_BYTES64);
> + PRINT_TSTAT_JSON(u32, "backlog_bytes", BACKLOG_BYTES);
> + PRINT_TSTAT_JSON(u32, "target_us", TARGET_US);
> + PRINT_TSTAT_JSON(u32, "interval_us", INTERVAL_US);
> + PRINT_TSTAT_JSON(u32, "peak_delay_us", PEAK_DELAY_US);
> + PRINT_TSTAT_JSON(u32, "avg_delay_us", AVG_DELAY_US);
> + PRINT_TSTAT_JSON(u32, "base_delay_us", BASE_DELAY_US);
> + PRINT_TSTAT_JSON(u32, "sent_packets", SENT_PACKETS);
> + PRINT_TSTAT_JSON(u32, "way_indirect_hits", WAY_INDIRECT_HITS);
> + PRINT_TSTAT_JSON(u32, "way_misses", WAY_MISSES);
> + PRINT_TSTAT_JSON(u32, "way_collisions", WAY_COLLISIONS);
> + PRINT_TSTAT_JSON(u32, "drops", DROPPED_PACKETS);
> + PRINT_TSTAT_JSON(u32, "ecn_mark", ECN_MARKED_PACKETS);
> + PRINT_TSTAT_JSON(u32, "ack_drops", ACKS_DROPPED_PACKETS);
> + PRINT_TSTAT_JSON(u32, "sparse_flows", SPARSE_FLOWS);
> + PRINT_TSTAT_JSON(u32, "bulk_flows", BULK_FLOWS);
> + PRINT_TSTAT_JSON(u32, "unresponsive_flows", UNRESPONSIVE_FLOWS);
> + PRINT_TSTAT_JSON(u32, "max_pkt_len", MAX_SKBLEN);
> + PRINT_TSTAT_JSON(u32, "flow_quantum", FLOW_QUANTUM);
> + close_json_object();
> +
> +#undef PRINT_TSTAT_JSON
> +}
> +
> +static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
> + struct rtattr *xstats)
> +{
> + SPRINT_BUF(b1);
> + struct rtattr *st[TCA_CAKE_STATS_MAX + 1];
> + int i;
> +
> + if (xstats == NULL)
> + return 0;
> +
> +#define GET_STAT_U32(attr) rta_getattr_u32(st[TCA_CAKE_STATS_ ## attr])
> +#define GET_STAT_S32(attr) (*(__s32*)RTA_DATA(st[TCA_CAKE_STATS_ ## attr]))
> +#define GET_STAT_U64(attr) rta_getattr_u64(st[TCA_CAKE_STATS_ ## attr])
> +
> + parse_rtattr_nested(st, TCA_CAKE_STATS_MAX, xstats);
> +
> + if (st[TCA_CAKE_STATS_MEMORY_USED] &&
> + st[TCA_CAKE_STATS_MEMORY_LIMIT]) {
> + print_string(PRINT_FP, NULL, " memory used: %s",
> + sprint_size(GET_STAT_U32(MEMORY_USED), b1));
> +
> + print_string(PRINT_FP, NULL, " of %s\n",
> + sprint_size(GET_STAT_U32(MEMORY_LIMIT), b1));
> +
> + print_uint(PRINT_JSON, "memory_used", NULL,
> + GET_STAT_U32(MEMORY_USED));
> + print_uint(PRINT_JSON, "memory_limit", NULL,
> + GET_STAT_U32(MEMORY_LIMIT));
> + }
> +
> + if (st[TCA_CAKE_STATS_CAPACITY_ESTIMATE64]) {
> + print_string(PRINT_FP, NULL, " capacity estimate: %s\n",
> + sprint_rate(GET_STAT_U64(CAPACITY_ESTIMATE64), b1));
> + print_uint(PRINT_JSON, "capacity_estimate", NULL,
> + GET_STAT_U64(CAPACITY_ESTIMATE64));
> + }
> +
> + if (st[TCA_CAKE_STATS_MIN_NETLEN] &&
> + st[TCA_CAKE_STATS_MAX_NETLEN]) {
> + print_uint(PRINT_ANY, "min_network_size",
> + " min/max network layer size: %12u",
> + GET_STAT_U32(MIN_NETLEN));
> + print_uint(PRINT_ANY, "max_network_size",
> + " /%8u\n", GET_STAT_U32(MAX_NETLEN));
> + }
> +
> + if (st[TCA_CAKE_STATS_MIN_ADJLEN] &&
> + st[TCA_CAKE_STATS_MAX_ADJLEN]) {
> + print_uint(PRINT_ANY, "min_adj_size",
> + " min/max overhead-adjusted size: %8u",
> + GET_STAT_U32(MIN_ADJLEN));
> + print_uint(PRINT_ANY, "max_adj_size",
> + " /%8u\n", GET_STAT_U32(MAX_ADJLEN));
> + }
> +
> + if (st[TCA_CAKE_STATS_AVG_NETOFF])
> + print_uint(PRINT_ANY, "avg_hdr_offset",
> + " average network hdr offset: %12u\n\n",
> + GET_STAT_U32(AVG_NETOFF));
> +
> + /* class stats */
> + if (st[TCA_CAKE_STATS_DEFICIT])
> + print_int(PRINT_ANY, "deficit", " deficit %u",
> + GET_STAT_S32(DEFICIT));
> + if (st[TCA_CAKE_STATS_COBALT_COUNT])
> + print_uint(PRINT_ANY, "count", " count %u",
> + GET_STAT_U32(COBALT_COUNT));
> +
> + if (st[TCA_CAKE_STATS_DROPPING] && GET_STAT_U32(DROPPING)) {
> + print_bool(PRINT_ANY, "dropping", " dropping", true);
> + if (st[TCA_CAKE_STATS_DROP_NEXT_US]) {
> + int drop_next = GET_STAT_S32(DROP_NEXT_US);
> + if (drop_next < 0) {
> + print_string(PRINT_FP, NULL, " drop_next -%s",
> + sprint_time(drop_next, b1));
> + } else {
> + print_uint(PRINT_JSON, "drop_next", NULL,
> + drop_next);
> + print_string(PRINT_FP, NULL, " drop_next %s",
> + sprint_time(drop_next, b1));
> + }
> + }
> + }
> +
> + if (st[TCA_CAKE_STATS_P_DROP]) {
> + print_uint(PRINT_ANY, "blue_prob", " blue_prob %u",
> + GET_STAT_U32(P_DROP));
> + if (st[TCA_CAKE_STATS_BLUE_TIMER_US]) {
> + int blue_timer = GET_STAT_S32(BLUE_TIMER_US);
> + if (blue_timer < 0) {
> + print_string(PRINT_FP, NULL, " blue_timer -%s",
> + sprint_time(blue_timer, b1));
> + } else {
> + print_uint(PRINT_JSON, "blue_timer", NULL,
> + blue_timer);
> + print_string(PRINT_FP, NULL, " blue_timer %s",
> + sprint_time(blue_timer, b1));
> + }
> + }
> + }
> +
> +#undef GET_STAT_U32
> +#undef GET_STAT_S32
> +#undef GET_STAT_U64
> +
> + if (st[TCA_CAKE_STATS_TIN_STATS]) {
> + struct rtattr *tins[TC_CAKE_MAX_TINS + 1];
> + struct rtattr *tstat[TC_CAKE_MAX_TINS][TCA_CAKE_TIN_STATS_MAX + 1];
> + int num_tins = 0;
> +
> + parse_rtattr_nested(tins, TC_CAKE_MAX_TINS, st[TCA_CAKE_STATS_TIN_STATS]);
> +
> + for (i = 1; i <= TC_CAKE_MAX_TINS && tins[i]; i++) {
> + parse_rtattr_nested(tstat[i-1], TCA_CAKE_TIN_STATS_MAX, tins[i]);
> + num_tins++;
> + }
> +
> + if (!num_tins)
> + return 0;
> +
> + if (is_json_context()) {
> + open_json_array(PRINT_JSON, "tins");
> + for (i = 0; i < num_tins; i++)
> + cake_print_json_tin(tstat[i]);
> + close_json_array(PRINT_JSON, NULL);
> +
> + return 0;
> + }
> +
> +
> + switch(num_tins) {
> + case 3:
> + fprintf(f, " Bulk Best Effort Voice\n");
> + break;
> +
> + case 4:
> + fprintf(f, " Bulk Best Effort Video Voice\n");
> + break;
> +
> + default:
> + fprintf(f, " ");
> + for(i=0; i < num_tins; i++)
> + fprintf(f, " Tin %u", i);
> + fprintf(f, "\n");
> + };
> +
> +#define GET_TSTAT(i, attr) (tstat[i][TCA_CAKE_TIN_STATS_ ## attr])
> +#define PRINT_TSTAT(name, attr, fmts, val) do { \
> + if (GET_TSTAT(0, attr)) { \
> + fprintf(f, name); \
> + for (i = 0; i < num_tins; i++) \
> + fprintf(f, " %12" fmts, val); \
> + fprintf(f, "\n"); \
> + } \
> + } while (0)
> +
> +#define SPRINT_TSTAT(pfunc, type, name, attr) PRINT_TSTAT( \
> + name, attr, "s", sprint_ ## pfunc( \
> + rta_getattr_ ## type(GET_TSTAT(i, attr)), b1))
> +
> +#define PRINT_TSTAT_U32(name, attr) PRINT_TSTAT( \
> + name, attr, "u", rta_getattr_u32(GET_TSTAT(i, attr)))
> +
> +#define PRINT_TSTAT_U64(name, attr) PRINT_TSTAT( \
> + name, attr, "llu", rta_getattr_u64(GET_TSTAT(i, attr)))
> +
> + SPRINT_TSTAT(rate, u64, " thresh ", THRESHOLD_RATE64);
> + SPRINT_TSTAT(time, u32, " target ", TARGET_US);
> + SPRINT_TSTAT(time, u32, " interval", INTERVAL_US);
> + SPRINT_TSTAT(time, u32, " pk_delay", PEAK_DELAY_US);
> + SPRINT_TSTAT(time, u32, " av_delay", AVG_DELAY_US);
> + SPRINT_TSTAT(time, u32, " sp_delay", BASE_DELAY_US);
> + SPRINT_TSTAT(size, u32, " backlog ", BACKLOG_BYTES);
> +
> + PRINT_TSTAT_U32(" pkts ", SENT_PACKETS);
> + PRINT_TSTAT_U64(" bytes ", SENT_BYTES64);
> +
> + PRINT_TSTAT_U32(" way_inds", WAY_INDIRECT_HITS);
> + PRINT_TSTAT_U32(" way_miss", WAY_MISSES);
> + PRINT_TSTAT_U32(" way_cols", WAY_COLLISIONS);
> + PRINT_TSTAT_U32(" drops ", DROPPED_PACKETS);
> + PRINT_TSTAT_U32(" marks ", ECN_MARKED_PACKETS);
> + PRINT_TSTAT_U32(" ack_drop", ACKS_DROPPED_PACKETS);
> + PRINT_TSTAT_U32(" sp_flows", SPARSE_FLOWS);
> + PRINT_TSTAT_U32(" bk_flows", BULK_FLOWS);
> + PRINT_TSTAT_U32(" un_flows", UNRESPONSIVE_FLOWS);
> + PRINT_TSTAT_U32(" max_len ", MAX_SKBLEN);
> + PRINT_TSTAT_U32(" quantum ", FLOW_QUANTUM);
I do agree that the above is simpler with macros than expanded into
functions.
More information about the Cake
mailing list