From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pg1-x541.google.com (mail-pg1-x541.google.com [IPv6:2607:f8b0:4864:20::541]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.bufferbloat.net (Postfix) with ESMTPS id E4B723B2A4 for ; Tue, 17 Jul 2018 22:31:47 -0400 (EDT) Received: by mail-pg1-x541.google.com with SMTP id p23-v6so1265832pgv.13 for ; Tue, 17 Jul 2018 19:31:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=KIJvPdw/kCQll59LkP1rgAte7HQ2RFsqEQO/8HpZmMI=; b=ISNkV7k7lF1SUc1FYOtxTIDXfoNl5xhjqYbrL/i/NLhEneL6PnfxeDpRAiD3VreYps 0zwXwnKUVpOeC545tVhmF5VvAqnXEZWXdqMr6MqCz+QsXddECvgLYMsk+jCuWpDxEZph GMe5/68lrnkNYBw9zo5i15nsgiwL69nQW/wIkeXTxDlKQDGsCFab7dabv4jDknEZf+7Y wUHW06Jg3bdsoS4QGwS1Q3ZWrv4NPaBzaiUwrWsSQ7X6yEIu75zjxHtFFM9VAXvaS+BB qjyLJGK+qMKl7r/Y6mIUS1GkkqQbhVAKtmXSAEscmPuxchONBpZ6mJfHwgsYzFfmg7va 24vw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=KIJvPdw/kCQll59LkP1rgAte7HQ2RFsqEQO/8HpZmMI=; b=Prkxoy3IXSuDPCbu+qihehWbdxJSwhGcUUO/NdNsEPhzYRvGkqfyw9ccSvwN7xghqL j6CWOG8kT75Wumv8dO7CiAQc485OfqL8qsBFzYleVilb5RtesywF3wFl5x3fGz3lTnyi O5vBsUHEw9lU0FKWqkVrQl+FsrA0M6uYpXAc96et84VwlreDbzAwUVB6RSt0mCmhuLGW 25aAR/pBJE37c0nbyfSNb+Qmz+XC0/6lqa5yn5dLOa9EG7N4cpKiT1qo71iEGZtnOsQs zQGOQDeqAQyyXMPYr7C63BXbOekOmZ8sl1YLrX+80raSGygAPS/ie0+PxSebD7gQXqzQ Soyw== X-Gm-Message-State: AOUpUlEGqB+/yzzmRMu9rFUF9TTovUGLKv7FS8LGHNnEnMhsm/+UQNXu jPQVKcVcwOX4Q7TEyPdrAug= X-Google-Smtp-Source: AAOMgpe4AyOb6sseQNRSDm5RWbPMp8shIYSLI2nbB04n8g8ZFGFRuSB2n9VcEc9Lp+F/8wR/J1P/Ew== X-Received: by 2002:a62:4147:: with SMTP id o68-v6mr3185250pfa.111.1531881106929; Tue, 17 Jul 2018 19:31:46 -0700 (PDT) Received: from dsa-mb.local ([2601:282:800:fd80:442b:d01f:635c:39ec]) by smtp.googlemail.com with ESMTPSA id w11-v6sm3120170pgm.82.2018.07.17.19.31.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Jul 2018 19:31:45 -0700 (PDT) To: =?UTF-8?Q?Toke_H=c3=b8iland-J=c3=b8rgensen?= , netdev@vger.kernel.org Cc: cake@lists.bufferbloat.net, Dave Taht References: <20180716163926.4826-1-toke@toke.dk> From: David Ahern Message-ID: Date: Tue, 17 Jul 2018 20:31:43 -0600 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 In-Reply-To: <20180716163926.4826-1-toke@toke.dk> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 8bit X-Mailman-Approved-At: Wed, 18 Jul 2018 12:25:08 -0400 Subject: Re: [Cake] [PATCH iproute2-next v10] Add support for CAKE qdisc X-BeenThere: cake@lists.bufferbloat.net X-Mailman-Version: 2.1.20 Precedence: list List-Id: Cake - FQ_codel the next generation List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 18 Jul 2018 02:31:48 -0000 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.