[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