Blame tc/q_cbq.c

Packit Service 3880ab
/*
Packit Service 3880ab
 * q_cbq.c		CBQ.
Packit Service 3880ab
 *
Packit Service 3880ab
 *		This program is free software; you can redistribute it and/or
Packit Service 3880ab
 *		modify it under the terms of the GNU General Public License
Packit Service 3880ab
 *		as published by the Free Software Foundation; either version
Packit Service 3880ab
 *		2 of the License, or (at your option) any later version.
Packit Service 3880ab
 *
Packit Service 3880ab
 * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
Packit Service 3880ab
 *
Packit Service 3880ab
 */
Packit Service 3880ab
Packit Service 3880ab
#include <stdio.h>
Packit Service 3880ab
#include <stdlib.h>
Packit Service 3880ab
#include <unistd.h>
Packit Service 3880ab
#include <fcntl.h>
Packit Service 3880ab
#include <sys/socket.h>
Packit Service 3880ab
#include <netinet/in.h>
Packit Service 3880ab
#include <arpa/inet.h>
Packit Service 3880ab
#include <string.h>
Packit Service 3880ab
Packit Service 3880ab
#include "utils.h"
Packit Service 3880ab
#include "tc_util.h"
Packit Service 3880ab
#include "tc_cbq.h"
Packit Service 3880ab
Packit Service 3880ab
static void explain_class(void)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr,
Packit Service 3880ab
		"Usage: ... cbq	bandwidth BPS rate BPS maxburst PKTS [ avpkt BYTES ]\n"
Packit Service 3880ab
		"		[ minburst PKTS ] [ bounded ] [ isolated ]\n"
Packit Service 3880ab
		"		[ allot BYTES ] [ mpu BYTES ] [ weight RATE ]\n"
Packit Service 3880ab
		"		[ prio NUMBER ] [ cell BYTES ] [ ewma LOG ]\n"
Packit Service 3880ab
		"		[ estimator INTERVAL TIME_CONSTANT ]\n"
Packit Service 3880ab
		"		[ split CLASSID ] [ defmap MASK/CHANGE ]\n"
Packit Service 3880ab
		"		[ overhead BYTES ] [ linklayer TYPE ]\n");
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void explain(void)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr,
Packit Service 3880ab
		"Usage: ... cbq bandwidth BPS avpkt BYTES [ mpu BYTES ]\n"
Packit Service 3880ab
		"               [ cell BYTES ] [ ewma LOG ]\n");
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static void explain1(char *arg)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr, "Illegal \"%s\"\n", arg);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
Packit Service 3880ab
static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
Packit Service 3880ab
{
Packit Service 3880ab
	struct tc_ratespec r = {};
Packit Service 3880ab
	struct tc_cbq_lssopt lss = {};
Packit Service 3880ab
	__u32 rtab[256];
Packit Service 3880ab
	unsigned mpu = 0, avpkt = 0, allot = 0;
Packit Service 3880ab
	unsigned short overhead = 0;
Packit Service 3880ab
	unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
Packit Service 3880ab
	int cell_log =  -1;
Packit Service 3880ab
	int ewma_log =  -1;
Packit Service 3880ab
	struct rtattr *tail;
Packit Service 3880ab
Packit Service 3880ab
	while (argc > 0) {
Packit Service 3880ab
		if (matches(*argv, "bandwidth") == 0 ||
Packit Service 3880ab
		    matches(*argv, "rate") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (strchr(*argv, '%')) {
Packit Service 3880ab
				if (get_percent_rate(&r.rate, *argv, dev)) {
Packit Service 3880ab
					explain1("bandwidth");
Packit Service 3880ab
					return -1;
Packit Service 3880ab
				}
Packit Service 3880ab
			} else if (get_rate(&r.rate, *argv)) {
Packit Service 3880ab
				explain1("bandwidth");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "ewma") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_integer(&ewma_log, *argv, 0)) {
Packit Service 3880ab
				explain1("ewma");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			if (ewma_log > 31) {
Packit Service 3880ab
				fprintf(stderr, "ewma_log must be < 32\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "cell") == 0) {
Packit Service 3880ab
			unsigned int cell;
Packit Service 3880ab
			int i;
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_size(&cell, *argv)) {
Packit Service 3880ab
				explain1("cell");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			for (i = 0; i < 32; i++)
Packit Service 3880ab
				if ((1<
Packit Service 3880ab
					break;
Packit Service 3880ab
			if (i >= 32) {
Packit Service 3880ab
				fprintf(stderr, "cell must be 2^n\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			cell_log = i;
Packit Service 3880ab
		} else if (matches(*argv, "avpkt") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_size(&avpkt, *argv)) {
Packit Service 3880ab
				explain1("avpkt");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "mpu") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_size(&mpu, *argv)) {
Packit Service 3880ab
				explain1("mpu");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "allot") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			/* Accept and ignore "allot" for backward compatibility */
Packit Service 3880ab
			if (get_size(&allot, *argv)) {
Packit Service 3880ab
				explain1("allot");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "overhead") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u16(&overhead, *argv, 10)) {
Packit Service 3880ab
				explain1("overhead"); return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "linklayer") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_linklayer(&linklayer, *argv)) {
Packit Service 3880ab
				explain1("linklayer"); return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "help") == 0) {
Packit Service 3880ab
			explain();
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		} else {
Packit Service 3880ab
			fprintf(stderr, "What is \"%s\"?\n", *argv);
Packit Service 3880ab
			explain();
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
		argc--; argv++;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	/* OK. All options are parsed. */
Packit Service 3880ab
Packit Service 3880ab
	if (r.rate == 0) {
Packit Service 3880ab
		fprintf(stderr, "CBQ: bandwidth is required parameter.\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
	if (avpkt == 0) {
Packit Service 3880ab
		fprintf(stderr, "CBQ: \"avpkt\" is required.\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
	if (allot < (avpkt*3)/2)
Packit Service 3880ab
		allot = (avpkt*3)/2;
Packit Service 3880ab
Packit Service 3880ab
	r.mpu = mpu;
Packit Service 3880ab
	r.overhead = overhead;
Packit Service 3880ab
	if (tc_calc_rtable(&r, rtab, cell_log, allot, linklayer) < 0) {
Packit Service 3880ab
		fprintf(stderr, "CBQ: failed to calculate rate table.\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (ewma_log < 0)
Packit Service 3880ab
		ewma_log = TC_CBQ_DEF_EWMA;
Packit Service 3880ab
	lss.ewma_log = ewma_log;
Packit Service 3880ab
	lss.maxidle = tc_calc_xmittime(r.rate, avpkt);
Packit Service 3880ab
	lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
Packit Service 3880ab
	lss.avpkt = avpkt;
Packit Service 3880ab
Packit Service 3880ab
	tail = addattr_nest(n, 1024, TCA_OPTIONS);
Packit Service 3880ab
	addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
Packit Service 3880ab
	addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
Packit Service 3880ab
	addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
Packit Service 3880ab
	if (show_raw) {
Packit Service 3880ab
		int i;
Packit Service 3880ab
Packit Service 3880ab
		for (i = 0; i < 256; i++)
Packit Service 3880ab
			printf("%u ", rtab[i]);
Packit Service 3880ab
		printf("\n");
Packit Service 3880ab
	}
Packit Service 3880ab
	addattr_nest_end(n, tail);
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
Packit Service 3880ab
{
Packit Service 3880ab
	int wrr_ok = 0, fopt_ok = 0;
Packit Service 3880ab
	struct tc_ratespec r = {};
Packit Service 3880ab
	struct tc_cbq_lssopt lss = {};
Packit Service 3880ab
	struct tc_cbq_wrropt wrr = {};
Packit Service 3880ab
	struct tc_cbq_fopt fopt = {};
Packit Service 3880ab
	__u32 rtab[256];
Packit Service 3880ab
	unsigned mpu = 0;
Packit Service 3880ab
	int cell_log =  -1;
Packit Service 3880ab
	int ewma_log =  -1;
Packit Service 3880ab
	unsigned int bndw = 0;
Packit Service 3880ab
	unsigned minburst = 0, maxburst = 0;
Packit Service 3880ab
	unsigned short overhead = 0;
Packit Service 3880ab
	unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
Packit Service 3880ab
	struct rtattr *tail;
Packit Service 3880ab
Packit Service 3880ab
	while (argc > 0) {
Packit Service 3880ab
		if (matches(*argv, "rate") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (strchr(*argv, '%')) {
Packit Service 3880ab
				if (get_percent_rate(&r.rate, *argv, dev)) {
Packit Service 3880ab
					explain1("rate");
Packit Service 3880ab
					return -1;
Packit Service 3880ab
				}
Packit Service 3880ab
			} else if (get_rate(&r.rate, *argv)) {
Packit Service 3880ab
				explain1("rate");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "bandwidth") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (strchr(*argv, '%')) {
Packit Service 3880ab
				if (get_percent_rate(&bndw, *argv, dev)) {
Packit Service 3880ab
					explain1("bandwidth");
Packit Service 3880ab
					return -1;
Packit Service 3880ab
				}
Packit Service 3880ab
			} else if (get_rate(&bndw, *argv)) {
Packit Service 3880ab
				explain1("bandwidth");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "minidle") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u32(&lss.minidle, *argv, 0)) {
Packit Service 3880ab
				explain1("minidle");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_MINIDLE;
Packit Service 3880ab
		} else if (matches(*argv, "minburst") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u32(&minburst, *argv, 0)) {
Packit Service 3880ab
				explain1("minburst");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_OFFTIME;
Packit Service 3880ab
		} else if (matches(*argv, "maxburst") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u32(&maxburst, *argv, 0)) {
Packit Service 3880ab
				explain1("maxburst");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_MAXIDLE;
Packit Service 3880ab
		} else if (matches(*argv, "bounded") == 0) {
Packit Service 3880ab
			lss.flags |= TCF_CBQ_LSS_BOUNDED;
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_FLAGS;
Packit Service 3880ab
		} else if (matches(*argv, "borrow") == 0) {
Packit Service 3880ab
			lss.flags &= ~TCF_CBQ_LSS_BOUNDED;
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_FLAGS;
Packit Service 3880ab
		} else if (matches(*argv, "isolated") == 0) {
Packit Service 3880ab
			lss.flags |= TCF_CBQ_LSS_ISOLATED;
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_FLAGS;
Packit Service 3880ab
		} else if (matches(*argv, "sharing") == 0) {
Packit Service 3880ab
			lss.flags &= ~TCF_CBQ_LSS_ISOLATED;
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_FLAGS;
Packit Service 3880ab
		} else if (matches(*argv, "ewma") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_integer(&ewma_log, *argv, 0)) {
Packit Service 3880ab
				explain1("ewma");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			if (ewma_log > 31) {
Packit Service 3880ab
				fprintf(stderr, "ewma_log must be < 32\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_EWMA;
Packit Service 3880ab
		} else if (matches(*argv, "cell") == 0) {
Packit Service 3880ab
			unsigned int cell;
Packit Service 3880ab
			int i;
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_size(&cell, *argv)) {
Packit Service 3880ab
				explain1("cell");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			for (i = 0; i < 32; i++)
Packit Service 3880ab
				if ((1<
Packit Service 3880ab
					break;
Packit Service 3880ab
			if (i >= 32) {
Packit Service 3880ab
				fprintf(stderr, "cell must be 2^n\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			cell_log = i;
Packit Service 3880ab
		} else if (matches(*argv, "prio") == 0) {
Packit Service 3880ab
			unsigned int prio;
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u32(&prio, *argv, 0)) {
Packit Service 3880ab
				explain1("prio");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			if (prio > TC_CBQ_MAXPRIO) {
Packit Service 3880ab
				fprintf(stderr, "\"prio\" must be number in the range 1...%d\n", TC_CBQ_MAXPRIO);
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			wrr.priority = prio;
Packit Service 3880ab
			wrr_ok++;
Packit Service 3880ab
		} else if (matches(*argv, "allot") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_size(&wrr.allot, *argv)) {
Packit Service 3880ab
				explain1("allot");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "avpkt") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_size(&lss.avpkt, *argv)) {
Packit Service 3880ab
				explain1("avpkt");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			lss.change |= TCF_CBQ_LSS_AVPKT;
Packit Service 3880ab
		} else if (matches(*argv, "mpu") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_size(&mpu, *argv)) {
Packit Service 3880ab
				explain1("mpu");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "weight") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_size(&wrr.weight, *argv)) {
Packit Service 3880ab
				explain1("weight");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			wrr_ok++;
Packit Service 3880ab
		} else if (matches(*argv, "split") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_tc_classid(&fopt.split, *argv)) {
Packit Service 3880ab
				fprintf(stderr, "Invalid split node ID.\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			fopt_ok++;
Packit Service 3880ab
		} else if (matches(*argv, "defmap") == 0) {
Packit Service 3880ab
			int err;
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange);
Packit Service 3880ab
			if (err < 1) {
Packit Service 3880ab
				fprintf(stderr, "Invalid defmap, should be MASK32[/MASK]\n");
Packit Service 3880ab
				return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
			if (err == 1)
Packit Service 3880ab
				fopt.defchange = ~0;
Packit Service 3880ab
			fopt_ok++;
Packit Service 3880ab
		} else if (matches(*argv, "overhead") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_u16(&overhead, *argv, 10)) {
Packit Service 3880ab
				explain1("overhead"); return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "linklayer") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (get_linklayer(&linklayer, *argv)) {
Packit Service 3880ab
				explain1("linklayer"); return -1;
Packit Service 3880ab
			}
Packit Service 3880ab
		} else if (matches(*argv, "help") == 0) {
Packit Service 3880ab
			explain_class();
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		} else {
Packit Service 3880ab
			fprintf(stderr, "What is \"%s\"?\n", *argv);
Packit Service 3880ab
			explain_class();
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
		argc--; argv++;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	/* OK. All options are parsed. */
Packit Service 3880ab
Packit Service 3880ab
	/* 1. Prepare link sharing scheduler parameters */
Packit Service 3880ab
	if (r.rate) {
Packit Service 3880ab
		unsigned int pktsize = wrr.allot;
Packit Service 3880ab
Packit Service 3880ab
		if (wrr.allot < (lss.avpkt*3)/2)
Packit Service 3880ab
			wrr.allot = (lss.avpkt*3)/2;
Packit Service 3880ab
		r.mpu = mpu;
Packit Service 3880ab
		r.overhead = overhead;
Packit Service 3880ab
		if (tc_calc_rtable(&r, rtab, cell_log, pktsize, linklayer) < 0) {
Packit Service 3880ab
			fprintf(stderr, "CBQ: failed to calculate rate table.\n");
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
	if (ewma_log < 0)
Packit Service 3880ab
		ewma_log = TC_CBQ_DEF_EWMA;
Packit Service 3880ab
	lss.ewma_log = ewma_log;
Packit Service 3880ab
	if (lss.change&(TCF_CBQ_LSS_OFFTIME|TCF_CBQ_LSS_MAXIDLE)) {
Packit Service 3880ab
		if (lss.avpkt == 0) {
Packit Service 3880ab
			fprintf(stderr, "CBQ: avpkt is required for max/minburst.\n");
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
		if (bndw == 0 || r.rate == 0) {
Packit Service 3880ab
			fprintf(stderr, "CBQ: bandwidth&rate are required for max/minburst.\n");
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
	if (wrr.priority == 0 && (n->nlmsg_flags&NLM_F_EXCL)) {
Packit Service 3880ab
		wrr_ok = 1;
Packit Service 3880ab
		wrr.priority = TC_CBQ_MAXPRIO;
Packit Service 3880ab
		if (wrr.allot == 0)
Packit Service 3880ab
			wrr.allot = (lss.avpkt*3)/2;
Packit Service 3880ab
	}
Packit Service 3880ab
	if (wrr_ok) {
Packit Service 3880ab
		if (wrr.weight == 0)
Packit Service 3880ab
			wrr.weight = (wrr.priority == TC_CBQ_MAXPRIO) ? 1 : r.rate;
Packit Service 3880ab
		if (wrr.allot == 0) {
Packit Service 3880ab
			fprintf(stderr, "CBQ: \"allot\" is required to set WRR parameters.\n");
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
	if (lss.change&TCF_CBQ_LSS_MAXIDLE) {
Packit Service 3880ab
		lss.maxidle = tc_cbq_calc_maxidle(bndw, r.rate, lss.avpkt, ewma_log, maxburst);
Packit Service 3880ab
		lss.change |= TCF_CBQ_LSS_MAXIDLE;
Packit Service 3880ab
		lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
Packit Service 3880ab
	}
Packit Service 3880ab
	if (lss.change&TCF_CBQ_LSS_OFFTIME) {
Packit Service 3880ab
		lss.offtime = tc_cbq_calc_offtime(bndw, r.rate, lss.avpkt, ewma_log, minburst);
Packit Service 3880ab
		lss.change |= TCF_CBQ_LSS_OFFTIME;
Packit Service 3880ab
		lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
Packit Service 3880ab
	}
Packit Service 3880ab
	if (lss.change&TCF_CBQ_LSS_MINIDLE) {
Packit Service 3880ab
		lss.minidle <<= lss.ewma_log;
Packit Service 3880ab
		lss.change |= TCF_CBQ_LSS_EWMA;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	tail = addattr_nest(n, 1024, TCA_OPTIONS);
Packit Service 3880ab
	if (lss.change) {
Packit Service 3880ab
		lss.change |= TCF_CBQ_LSS_FLAGS;
Packit Service 3880ab
		addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
Packit Service 3880ab
	}
Packit Service 3880ab
	if (wrr_ok)
Packit Service 3880ab
		addattr_l(n, 1024, TCA_CBQ_WRROPT, &wrr, sizeof(wrr));
Packit Service 3880ab
	if (fopt_ok)
Packit Service 3880ab
		addattr_l(n, 1024, TCA_CBQ_FOPT, &fopt, sizeof(fopt));
Packit Service 3880ab
	if (r.rate) {
Packit Service 3880ab
		addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
Packit Service 3880ab
		addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
Packit Service 3880ab
		if (show_raw) {
Packit Service 3880ab
			int i;
Packit Service 3880ab
Packit Service 3880ab
			for (i = 0; i < 256; i++)
Packit Service 3880ab
				printf("%u ", rtab[i]);
Packit Service 3880ab
			printf("\n");
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
	addattr_nest_end(n, tail);
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
Packit Service 3880ab
static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
Packit Service 3880ab
{
Packit Service 3880ab
	struct rtattr *tb[TCA_CBQ_MAX+1];
Packit Service 3880ab
	struct tc_ratespec *r = NULL;
Packit Service 3880ab
	struct tc_cbq_lssopt *lss = NULL;
Packit Service 3880ab
	struct tc_cbq_wrropt *wrr = NULL;
Packit Service 3880ab
	struct tc_cbq_fopt *fopt = NULL;
Packit Service 3880ab
	struct tc_cbq_ovl *ovl = NULL;
Packit Service 3880ab
	unsigned int linklayer;
Packit Service 3880ab
Packit Service 3880ab
	SPRINT_BUF(b1);
Packit Service 3880ab
	SPRINT_BUF(b2);
Packit Service 3880ab
Packit Service 3880ab
	if (opt == NULL)
Packit Service 3880ab
		return 0;
Packit Service 3880ab
Packit Service 3880ab
	parse_rtattr_nested(tb, TCA_CBQ_MAX, opt);
Packit Service 3880ab
Packit Service 3880ab
	if (tb[TCA_CBQ_RATE]) {
Packit Service 3880ab
		if (RTA_PAYLOAD(tb[TCA_CBQ_RATE]) < sizeof(*r))
Packit Service 3880ab
			fprintf(stderr, "CBQ: too short rate opt\n");
Packit Service 3880ab
		else
Packit Service 3880ab
			r = RTA_DATA(tb[TCA_CBQ_RATE]);
Packit Service 3880ab
	}
Packit Service 3880ab
	if (tb[TCA_CBQ_LSSOPT]) {
Packit Service 3880ab
		if (RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT]) < sizeof(*lss))
Packit Service 3880ab
			fprintf(stderr, "CBQ: too short lss opt\n");
Packit Service 3880ab
		else
Packit Service 3880ab
			lss = RTA_DATA(tb[TCA_CBQ_LSSOPT]);
Packit Service 3880ab
	}
Packit Service 3880ab
	if (tb[TCA_CBQ_WRROPT]) {
Packit Service 3880ab
		if (RTA_PAYLOAD(tb[TCA_CBQ_WRROPT]) < sizeof(*wrr))
Packit Service 3880ab
			fprintf(stderr, "CBQ: too short wrr opt\n");
Packit Service 3880ab
		else
Packit Service 3880ab
			wrr = RTA_DATA(tb[TCA_CBQ_WRROPT]);
Packit Service 3880ab
	}
Packit Service 3880ab
	if (tb[TCA_CBQ_FOPT]) {
Packit Service 3880ab
		if (RTA_PAYLOAD(tb[TCA_CBQ_FOPT]) < sizeof(*fopt))
Packit Service 3880ab
			fprintf(stderr, "CBQ: too short fopt\n");
Packit Service 3880ab
		else
Packit Service 3880ab
			fopt = RTA_DATA(tb[TCA_CBQ_FOPT]);
Packit Service 3880ab
	}
Packit Service 3880ab
	if (tb[TCA_CBQ_OVL_STRATEGY]) {
Packit Service 3880ab
		if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl))
Packit Service 3880ab
			fprintf(stderr, "CBQ: too short overlimit strategy %u/%u\n",
Packit Service 3880ab
				(unsigned int) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]),
Packit Service 3880ab
				(unsigned int) sizeof(*ovl));
Packit Service 3880ab
		else
Packit Service 3880ab
			ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]);
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (r) {
Packit Service 3880ab
		char buf[64];
Packit Service 3880ab
Packit Service 3880ab
		print_rate(buf, sizeof(buf), r->rate);
Packit Service 3880ab
		fprintf(f, "rate %s ", buf);
Packit Service 3880ab
		linklayer = (r->linklayer & TC_LINKLAYER_MASK);
Packit Service 3880ab
		if (linklayer > TC_LINKLAYER_ETHERNET || show_details)
Packit Service 3880ab
			fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b2));
Packit Service 3880ab
		if (show_details) {
Packit Service 3880ab
			fprintf(f, "cell %ub ", 1<<r->cell_log);
Packit Service 3880ab
			if (r->mpu)
Packit Service 3880ab
				fprintf(f, "mpu %ub ", r->mpu);
Packit Service 3880ab
			if (r->overhead)
Packit Service 3880ab
				fprintf(f, "overhead %ub ", r->overhead);
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
	if (lss && lss->flags) {
Packit Service 3880ab
		int comma = 0;
Packit Service 3880ab
Packit Service 3880ab
		fprintf(f, "(");
Packit Service 3880ab
		if (lss->flags&TCF_CBQ_LSS_BOUNDED) {
Packit Service 3880ab
			fprintf(f, "bounded");
Packit Service 3880ab
			comma = 1;
Packit Service 3880ab
		}
Packit Service 3880ab
		if (lss->flags&TCF_CBQ_LSS_ISOLATED) {
Packit Service 3880ab
			if (comma)
Packit Service 3880ab
				fprintf(f, ",");
Packit Service 3880ab
			fprintf(f, "isolated");
Packit Service 3880ab
		}
Packit Service 3880ab
		fprintf(f, ") ");
Packit Service 3880ab
	}
Packit Service 3880ab
	if (wrr) {
Packit Service 3880ab
		if (wrr->priority != TC_CBQ_MAXPRIO)
Packit Service 3880ab
			fprintf(f, "prio %u", wrr->priority);
Packit Service 3880ab
		else
Packit Service 3880ab
			fprintf(f, "prio no-transmit");
Packit Service 3880ab
		if (show_details) {
Packit Service 3880ab
			char buf[64];
Packit Service 3880ab
Packit Service 3880ab
			fprintf(f, "/%u ", wrr->cpriority);
Packit Service 3880ab
			if (wrr->weight != 1) {
Packit Service 3880ab
				print_rate(buf, sizeof(buf), wrr->weight);
Packit Service 3880ab
				fprintf(f, "weight %s ", buf);
Packit Service 3880ab
			}
Packit Service 3880ab
			if (wrr->allot)
Packit Service 3880ab
				fprintf(f, "allot %ub ", wrr->allot);
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
	if (lss && show_details) {
Packit Service 3880ab
		fprintf(f, "\nlevel %u ewma %u avpkt %ub ", lss->level, lss->ewma_log, lss->avpkt);
Packit Service 3880ab
		if (lss->maxidle) {
Packit Service 3880ab
			fprintf(f, "maxidle %s ", sprint_ticks(lss->maxidle>>lss->ewma_log, b1));
Packit Service 3880ab
			if (show_raw)
Packit Service 3880ab
				fprintf(f, "[%08x] ", lss->maxidle);
Packit Service 3880ab
		}
Packit Service 3880ab
		if (lss->minidle != 0x7fffffff) {
Packit Service 3880ab
			fprintf(f, "minidle %s ", sprint_ticks(lss->minidle>>lss->ewma_log, b1));
Packit Service 3880ab
			if (show_raw)
Packit Service 3880ab
				fprintf(f, "[%08x] ", lss->minidle);
Packit Service 3880ab
		}
Packit Service 3880ab
		if (lss->offtime) {
Packit Service 3880ab
			fprintf(f, "offtime %s ", sprint_ticks(lss->offtime, b1));
Packit Service 3880ab
			if (show_raw)
Packit Service 3880ab
				fprintf(f, "[%08x] ", lss->offtime);
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
	if (fopt && show_details) {
Packit Service 3880ab
		char buf[64];
Packit Service 3880ab
Packit Service 3880ab
		print_tc_classid(buf, sizeof(buf), fopt->split);
Packit Service 3880ab
		fprintf(f, "\nsplit %s ", buf);
Packit Service 3880ab
		if (fopt->defmap) {
Packit Service 3880ab
			fprintf(f, "defmap %08x", fopt->defmap);
Packit Service 3880ab
		}
Packit Service 3880ab
	}
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int cbq_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
Packit Service 3880ab
{
Packit Service 3880ab
	struct tc_cbq_xstats *st;
Packit Service 3880ab
Packit Service 3880ab
	if (xstats == NULL)
Packit Service 3880ab
		return 0;
Packit Service 3880ab
Packit Service 3880ab
	if (RTA_PAYLOAD(xstats) < sizeof(*st))
Packit Service 3880ab
		return -1;
Packit Service 3880ab
Packit Service 3880ab
	st = RTA_DATA(xstats);
Packit Service 3880ab
	fprintf(f, "  borrowed %u overactions %u avgidle %g undertime %g", st->borrows,
Packit Service 3880ab
		st->overactions, (double)st->avgidle, (double)st->undertime);
Packit Service 3880ab
	return 0;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
struct qdisc_util cbq_qdisc_util = {
Packit Service 3880ab
	.id		= "cbq",
Packit Service 3880ab
	.parse_qopt	= cbq_parse_opt,
Packit Service 3880ab
	.print_qopt	= cbq_print_opt,
Packit Service 3880ab
	.print_xstats	= cbq_print_xstats,
Packit Service 3880ab
	.parse_copt	= cbq_parse_class_opt,
Packit Service 3880ab
	.print_copt	= cbq_print_opt,
Packit Service 3880ab
};