Example #1
0
int parse_size_table(int *argcp, char ***argvp, struct tc_sizespec *sp)
{
	char **argv = *argvp;
	int argc = *argcp;
	struct tc_sizespec s;

	memset(&s, 0, sizeof(s));

	NEXT_ARG();
	if (matches(*argv, "help") == 0) {
		stab_help();
		return -1;
	}
	while (argc > 0) {
		if (matches(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (s.mtu)
				duparg("mtu", *argv);
			if (get_u32(&s.mtu, *argv, 10))
				invarg("mtu", "invalid mtu");
		} else if (matches(*argv, "mpu") == 0) {
			NEXT_ARG();
			if (s.mpu)
				duparg("mpu", *argv);
			if (get_u32(&s.mpu, *argv, 10))
				invarg("mpu", "invalid mpu");
		} else if (matches(*argv, "overhead") == 0) {
			NEXT_ARG();
			if (s.overhead)
				duparg("overhead", *argv);
			if (get_integer(&s.overhead, *argv, 10))
				invarg("overhead", "invalid overhead");
		} else if (matches(*argv, "tsize") == 0) {
			NEXT_ARG();
			if (s.tsize)
				duparg("tsize", *argv);
			if (get_u32(&s.tsize, *argv, 10))
				invarg("tsize", "invalid table size");
		} else if (matches(*argv, "linklayer") == 0) {
			NEXT_ARG();
			if (s.linklayer != LINKLAYER_UNSPEC)
				duparg("linklayer", *argv);
			if (get_linklayer(&s.linklayer, *argv))
				invarg("linklayer", "invalid linklayer");
		} else
			break;
		argc--; argv++;
	}

	if (!check_size_table_opts(&s))
		return -1;

	*sp = s;
	*argvp = argv;
	*argcp = argc;
	return 0;
}
int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
{
	int argc = *argc_p;
	char **argv = *argv_p;
	int res = -1;
	int ok=0;
	struct tc_police p;
	__u32 rtab[256];
	__u32 ptab[256];
	__u32 avrate = 0;
	int presult = 0;
	unsigned buffer=0, mtu=0, mpu=0;
	unsigned short overhead=0;
	unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
	int Rcell_log=-1, Pcell_log = -1;
	struct rtattr *tail;

	memset(&p, 0, sizeof(p));
	p.action = TC_POLICE_RECLASSIFY;

	if (a) /* new way of doing things */
		NEXT_ARG();

	if (argc <= 0)
		return -1;

	while (argc > 0) {

		if (matches(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&p.index, *argv, 10)) {
				fprintf(stderr, "Illegal \"index\"\n");
				return -1;
			}
		} else if (matches(*argv, "burst") == 0 ||
			strcmp(*argv, "buffer") == 0 ||
			strcmp(*argv, "maxburst") == 0) {
			NEXT_ARG();
			if (buffer) {
				fprintf(stderr, "Double \"buffer/burst\" spec\n");
				return -1;
			}
			if (get_size_and_cell(&buffer, &Rcell_log, *argv) < 0) {
				explain1("buffer");
				return -1;
			}
		} else if (strcmp(*argv, "mtu") == 0 ||
			   strcmp(*argv, "minburst") == 0) {
			NEXT_ARG();
			if (mtu) {
				fprintf(stderr, "Double \"mtu/minburst\" spec\n");
				return -1;
			}
			if (get_size_and_cell(&mtu, &Pcell_log, *argv) < 0) {
				explain1("mtu");
				return -1;
			}
		} else if (strcmp(*argv, "mpu") == 0) {
			NEXT_ARG();
			if (mpu) {
				fprintf(stderr, "Double \"mpu\" spec\n");
				return -1;
			}
			if (get_size(&mpu, *argv)) {
				explain1("mpu");
				return -1;
			}
		} else if (strcmp(*argv, "rate") == 0) {
			NEXT_ARG();
			if (p.rate.rate) {
				fprintf(stderr, "Double \"rate\" spec\n");
				return -1;
			}
			if (get_rate(&p.rate.rate, *argv)) {
				explain1("rate");
				return -1;
			}
		} else if (strcmp(*argv, "avrate") == 0) {
			NEXT_ARG();
			if (avrate) {
				fprintf(stderr, "Double \"avrate\" spec\n");
				return -1;
			}
			if (get_rate(&avrate, *argv)) {
				explain1("avrate");
				return -1;
			}
		} else if (matches(*argv, "peakrate") == 0) {
			NEXT_ARG();
			if (p.peakrate.rate) {
				fprintf(stderr, "Double \"peakrate\" spec\n");
				return -1;
			}
			if (get_rate(&p.peakrate.rate, *argv)) {
				explain1("peakrate");
				return -1;
			}
		} else if (matches(*argv, "reclassify") == 0) {
			p.action = TC_POLICE_RECLASSIFY;
		} else if (matches(*argv, "drop") == 0 ||
			   matches(*argv, "shot") == 0) {
			p.action = TC_POLICE_SHOT;
		} else if (matches(*argv, "continue") == 0) {
			p.action = TC_POLICE_UNSPEC;
		} else if (matches(*argv, "pass") == 0) {
			p.action = TC_POLICE_OK;
		} else if (matches(*argv, "pipe") == 0) {
			p.action = TC_POLICE_PIPE;
		} else if (strcmp(*argv, "action") == 0 ||
			   strcmp(*argv, "conform-exceed") == 0) {
			NEXT_ARG();
			if (get_police_result(&p.action, &presult, *argv)) {
				fprintf(stderr, "Illegal \"action\"\n");
				return -1;
			}
		} else if (matches(*argv, "overhead") == 0) {
			NEXT_ARG();
			if (get_u16(&overhead, *argv, 10)) {
				explain1("overhead"); return -1;
			}
		} else if (matches(*argv, "linklayer") == 0) {
			NEXT_ARG();
			if (get_linklayer(&linklayer, *argv)) {
				explain1("linklayer"); return -1;
			}
		} else if (strcmp(*argv, "help") == 0) {
			usage();
		} else {
			break;
		}
		ok++;
		argc--; argv++;
	}

	if (!ok)
		return -1;

	if (p.rate.rate && !buffer) {
		fprintf(stderr, "\"burst\" requires \"rate\".\n");
		return -1;
	}
	if (p.peakrate.rate) {
		if (!p.rate.rate) {
			fprintf(stderr, "\"peakrate\" requires \"rate\".\n");
			return -1;
		}
		if (!mtu) {
			fprintf(stderr, "\"mtu\" is required, if \"peakrate\" is requested.\n");
			return -1;
		}
	}

	if (p.rate.rate) {
		p.rate.mpu = mpu;
		p.rate.overhead = overhead;
		if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
			fprintf(stderr, "TBF: failed to calculate rate table.\n");
			return -1;
		}
		p.burst = tc_calc_xmittime(p.rate.rate, buffer);
	}
	p.mtu = mtu;
	if (p.peakrate.rate) {
		p.peakrate.mpu = mpu;
		p.peakrate.overhead = overhead;
		if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) {
			fprintf(stderr, "POLICE: failed to calculate peak rate table.\n");
			return -1;
		}
	}

	tail = NLMSG_TAIL(n);
	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
	addattr_l(n, MAX_MSG, TCA_POLICE_TBF, &p, sizeof(p));
	if (p.rate.rate)
		addattr_l(n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024);
	if (p.peakrate.rate)
                addattr_l(n, MAX_MSG, TCA_POLICE_PEAKRATE, ptab, 1024);
	if (avrate)
		addattr32(n, MAX_MSG, TCA_POLICE_AVRATE, avrate);
	if (presult)
		addattr32(n, MAX_MSG, TCA_POLICE_RESULT, presult);

	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
	res = 0;

	*argc_p = argc;
	*argv_p = argv;
	return res;
}
Example #3
0
static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
{
    struct tc_ratespec r;
    struct tc_cbq_lssopt lss;
    __u32 rtab[256];
    unsigned mpu=0, avpkt=0, allot=0;
    unsigned short overhead=0;
    unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
    int cell_log=-1;
    int ewma_log=-1;
    struct rtattr *tail;

    memset(&lss, 0, sizeof(lss));
    memset(&r, 0, sizeof(r));

    while (argc > 0) {
        if (matches(*argv, "bandwidth") == 0 ||
                matches(*argv, "rate") == 0) {
            NEXT_ARG();
            if (get_rate(&r.rate, *argv)) {
                explain1("bandwidth");
                return -1;
            }
        } else if (matches(*argv, "ewma") == 0) {
            NEXT_ARG();
            if (get_integer(&ewma_log, *argv, 0)) {
                explain1("ewma");
                return -1;
            }
            if (ewma_log > 31) {
                fprintf(stderr, "ewma_log must be < 32\n");
                return -1;
            }
        } else if (matches(*argv, "cell") == 0) {
            unsigned cell;
            int i;
            NEXT_ARG();
            if (get_size(&cell, *argv)) {
                explain1("cell");
                return -1;
            }
            for (i=0; i<32; i++)
                if ((1<<i) == cell)
                    break;
            if (i>=32) {
                fprintf(stderr, "cell must be 2^n\n");
                return -1;
            }
            cell_log = i;
        } else if (matches(*argv, "avpkt") == 0) {
            NEXT_ARG();
            if (get_size(&avpkt, *argv)) {
                explain1("avpkt");
                return -1;
            }
        } else if (matches(*argv, "mpu") == 0) {
            NEXT_ARG();
            if (get_size(&mpu, *argv)) {
                explain1("mpu");
                return -1;
            }
        } else if (matches(*argv, "allot") == 0) {
            NEXT_ARG();
            /* Accept and ignore "allot" for backward compatibility */
            if (get_size(&allot, *argv)) {
                explain1("allot");
                return -1;
            }
        } else if (matches(*argv, "overhead") == 0) {
            NEXT_ARG();
            if (get_u16(&overhead, *argv, 10)) {
                explain1("overhead");
                return -1;
            }
        } else if (matches(*argv, "linklayer") == 0) {
            NEXT_ARG();
            if (get_linklayer(&linklayer, *argv)) {
                explain1("linklayer");
                return -1;
            }
        } else if (matches(*argv, "help") == 0) {
            explain();
            return -1;
        } else {
            fprintf(stderr, "What is \"%s\"?\n", *argv);
            explain();
            return -1;
        }
        argc--;
        argv++;
    }

    /* OK. All options are parsed. */

    if (r.rate == 0) {
        fprintf(stderr, "CBQ: bandwidth is required parameter.\n");
        return -1;
    }
    if (avpkt == 0) {
        fprintf(stderr, "CBQ: \"avpkt\" is required.\n");
        return -1;
    }
    if (allot < (avpkt*3)/2)
        allot = (avpkt*3)/2;

    r.mpu = mpu;
    r.overhead = overhead;
    if (tc_calc_rtable(&r, rtab, cell_log, allot, linklayer) < 0) {
        fprintf(stderr, "CBQ: failed to calculate rate table.\n");
        return -1;
    }

    if (ewma_log < 0)
        ewma_log = TC_CBQ_DEF_EWMA;
    lss.ewma_log = ewma_log;
    lss.maxidle = tc_calc_xmittime(r.rate, avpkt);
    lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
    lss.avpkt = avpkt;

    tail = NLMSG_TAIL(n);
    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
    addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
    addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
    addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
    if (show_raw) {
        int i;
        for (i=0; i<256; i++)
            printf("%u ", rtab[i]);
        printf("\n");
    }
    tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
    return 0;
}
Example #4
0
int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
{
	int ok=0;
	struct tc_htb_opt opt;
	__u32 * rtab = vmalloc(256*sizeof(__u32));
	__u32 * ctab = vmalloc(256*sizeof(__u32));
	unsigned buffer=0,cbuffer=0;
	int cell_log=-1,ccell_log = -1;
	unsigned mtu;
	unsigned short mpu = 0;
	unsigned short overhead = 0;
	unsigned int linklayer  = LINKLAYER_ETHERNET;
	struct rtattr *tail;

	memset(&opt, 0, sizeof(opt)); 
	mtu = 1600;

	while (argc > 0) {
		if (matches(*argv, "prio") == 0) {
			NEXT_ARG();
			if (get_u32(&opt.prio, *argv, 10)) {
				explain1("prio"); return -1;
			}
			ok++;
		} else if (matches(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (get_u32(&mtu, *argv, 10)) {
				explain1("mtu"); return -1;
			}
		} else if (matches(*argv, "mpu") == 0) {
			NEXT_ARG();
			if (get_u16(&mpu, *argv, 10)) {
				explain1("mpu"); return -1;
			}
		} else if (matches(*argv, "overhead") == 0) {
			NEXT_ARG();
			if (get_u16(&overhead, *argv, 10)) {
				explain1("overhead"); return -1;
			}
		} else if (matches(*argv, "linklayer") == 0) {
			NEXT_ARG();
			if (get_linklayer(&linklayer, *argv)) {
				explain1("linklayer"); return -1;
			}
		} else if (matches(*argv, "quantum") == 0) {
			NEXT_ARG();
			if (get_u32(&opt.quantum, *argv, 10)) {
				explain1("quantum"); return -1;
			}
		}    /* else if (matches(*argv, "burst") == 0 ||
			strcmp(*argv, "buffer") == 0 ||
			strcmp(*argv, "maxburst") == 0) {
			NEXT_ARG();
			if (get_size_and_cell(&buffer, &cell_log, *argv) < 0) {
				explain1("buffer");
				return -1;
			}
			ok++;
		} */ /* else if (matches(*argv, "cburst") == 0 ||
			strcmp(*argv, "cbuffer") == 0 ||
			strcmp(*argv, "cmaxburst") == 0) {
			NEXT_ARG(); 
			if (get_size_and_cell(&cbuffer, &ccell_log, *argv) < 0) {
				explain1("cbuffer");
				return -1;
			}
			ok++;
		} */ else if (strcmp(*argv, "ceil") == 0) {
			NEXT_ARG();
			if (opt.ceil.rate) {
				printk(KERN_DEBUG "[MTC] [Q_HTB] Double \"ceil\" spec\n");
				return -1;
			}
			if (get_rate(&opt.ceil.rate, *argv)) {
				explain1("ceil");
				return -1;
			}
			ok++;
		} else if (strcmp(*argv, "rate") == 0) {
			NEXT_ARG();
			if (opt.rate.rate) {
				printk(KERN_DEBUG "[MTC] [Q_HTB] Double \"rate\" spec\n");
				return -1;
			}
			if (get_rate(&opt.rate.rate, *argv)) {
				explain1("rate");
				return -1;
			}
			ok++;
		} else if (strcmp(*argv, "help") == 0) {
			return -1;
		} else {
			printk(KERN_DEBUG "[MTC] [Q_HTB] What is \"%s\"?\n", *argv);
			return -1;
		}
		argc--; argv++;
	}

/*	if (!ok)
		return 0;*/

	
	if (opt.rate.rate == 0) {
		printk(KERN_DEBUG "[MTC] [Q_HTB] \"rate\" is required.\n");
		return -1;
	}
	if (!opt.ceil.rate) opt.ceil = opt.rate;

	if (!buffer) buffer = opt.rate.rate / get_hz() + mtu;
	if (!cbuffer) cbuffer = opt.ceil.rate / get_hz() + mtu;
	
	opt.ceil.overhead = overhead;
	opt.rate.overhead = overhead;

	opt.ceil.mpu = mpu;
	opt.rate.mpu = mpu;

	if (tc_calc_rtable(&opt.rate, rtab, cell_log, mtu, linklayer) < 0) {
		printk(KERN_DEBUG "[MTC] [Q_HTB] error: failed to calculate rate table.\n");
		return -1;
	}
	opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
	
	
	if (tc_calc_rtable(&opt.ceil, ctab, ccell_log, mtu, linklayer) < 0) {
		printk(KERN_DEBUG "[MTC] [Q_HTB] error: failed to calculate ceil rate table.\n");
		return -1;
	}
	opt.cbuffer = tc_calc_xmittime(opt.ceil.rate, cbuffer);

	
	tail = NLMSG_TAIL(n);
	
	addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
	addattr_l(n, 2024, TCA_HTB_PARMS, &opt, sizeof(opt));
	addattr_l(n, 3024, TCA_HTB_RTAB, rtab, 1024);
	addattr_l(n, 4024, TCA_HTB_CTAB, ctab, 1024);
	
	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
	
	return 0;
}
Example #5
0
static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
{
    int wrr_ok=0, fopt_ok=0;
    struct tc_ratespec r;
    struct tc_cbq_lssopt lss;
    struct tc_cbq_wrropt wrr;
    struct tc_cbq_fopt fopt;
    struct tc_cbq_ovl ovl;
    __u32 rtab[256];
    unsigned mpu=0;
    int cell_log=-1;
    int ewma_log=-1;
    unsigned bndw = 0;
    unsigned minburst=0, maxburst=0;
    unsigned short overhead=0;
    unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
    struct rtattr *tail;

    memset(&r, 0, sizeof(r));
    memset(&lss, 0, sizeof(lss));
    memset(&wrr, 0, sizeof(wrr));
    memset(&fopt, 0, sizeof(fopt));
    memset(&ovl, 0, sizeof(ovl));

    while (argc > 0) {
        if (matches(*argv, "rate") == 0) {
            NEXT_ARG();
            if (get_rate(&r.rate, *argv)) {
                explain1("rate");
                return -1;
            }
        } else if (matches(*argv, "bandwidth") == 0) {
            NEXT_ARG();
            if (get_rate(&bndw, *argv)) {
                explain1("bandwidth");
                return -1;
            }
        } else if (matches(*argv, "minidle") == 0) {
            NEXT_ARG();
            if (get_u32(&lss.minidle, *argv, 0)) {
                explain1("minidle");
                return -1;
            }
            lss.change |= TCF_CBQ_LSS_MINIDLE;
        } else if (matches(*argv, "minburst") == 0) {
            NEXT_ARG();
            if (get_u32(&minburst, *argv, 0)) {
                explain1("minburst");
                return -1;
            }
            lss.change |= TCF_CBQ_LSS_OFFTIME;
        } else if (matches(*argv, "maxburst") == 0) {
            NEXT_ARG();
            if (get_u32(&maxburst, *argv, 0)) {
                explain1("maxburst");
                return -1;
            }
            lss.change |= TCF_CBQ_LSS_MAXIDLE;
        } else if (matches(*argv, "bounded") == 0) {
            lss.flags |= TCF_CBQ_LSS_BOUNDED;
            lss.change |= TCF_CBQ_LSS_FLAGS;
        } else if (matches(*argv, "borrow") == 0) {
            lss.flags &= ~TCF_CBQ_LSS_BOUNDED;
            lss.change |= TCF_CBQ_LSS_FLAGS;
        } else if (matches(*argv, "isolated") == 0) {
            lss.flags |= TCF_CBQ_LSS_ISOLATED;
            lss.change |= TCF_CBQ_LSS_FLAGS;
        } else if (matches(*argv, "sharing") == 0) {
            lss.flags &= ~TCF_CBQ_LSS_ISOLATED;
            lss.change |= TCF_CBQ_LSS_FLAGS;
        } else if (matches(*argv, "ewma") == 0) {
            NEXT_ARG();
            if (get_integer(&ewma_log, *argv, 0)) {
                explain1("ewma");
                return -1;
            }
            if (ewma_log > 31) {
                fprintf(stderr, "ewma_log must be < 32\n");
                return -1;
            }
            lss.change |= TCF_CBQ_LSS_EWMA;
        } else if (matches(*argv, "cell") == 0) {
            unsigned cell;
            int i;
            NEXT_ARG();
            if (get_size(&cell, *argv)) {
                explain1("cell");
                return -1;
            }
            for (i=0; i<32; i++)
                if ((1<<i) == cell)
                    break;
            if (i>=32) {
                fprintf(stderr, "cell must be 2^n\n");
                return -1;
            }
            cell_log = i;
        } else if (matches(*argv, "prio") == 0) {
            unsigned prio;
            NEXT_ARG();
            if (get_u32(&prio, *argv, 0)) {
                explain1("prio");
                return -1;
            }
            if (prio > TC_CBQ_MAXPRIO) {
                fprintf(stderr, "\"prio\" must be number in the range 1...%d\n", TC_CBQ_MAXPRIO);
                return -1;
            }
            wrr.priority = prio;
            wrr_ok++;
        } else if (matches(*argv, "allot") == 0) {
            NEXT_ARG();
            if (get_size(&wrr.allot, *argv)) {
                explain1("allot");
                return -1;
            }
        } else if (matches(*argv, "avpkt") == 0) {
            NEXT_ARG();
            if (get_size(&lss.avpkt, *argv)) {
                explain1("avpkt");
                return -1;
            }
            lss.change |= TCF_CBQ_LSS_AVPKT;
        } else if (matches(*argv, "mpu") == 0) {
            NEXT_ARG();
            if (get_size(&mpu, *argv)) {
                explain1("mpu");
                return -1;
            }
        } else if (matches(*argv, "weight") == 0) {
            NEXT_ARG();
            if (get_size(&wrr.weight, *argv)) {
                explain1("weight");
                return -1;
            }
            wrr_ok++;
        } else if (matches(*argv, "split") == 0) {
            NEXT_ARG();
            if (get_tc_classid(&fopt.split, *argv)) {
                fprintf(stderr, "Invalid split node ID.\n");
                usage();
            }
            fopt_ok++;
        } else if (matches(*argv, "defmap") == 0) {
            int err;
            NEXT_ARG();
            err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange);
            if (err < 1) {
                fprintf(stderr, "Invalid defmap, should be MASK32[/MASK]\n");
                return -1;
            }
            if (err == 1)
                fopt.defchange = ~0;
            fopt_ok++;
        } else if (matches(*argv, "overhead") == 0) {
            NEXT_ARG();
            if (get_u16(&overhead, *argv, 10)) {
                explain1("overhead");
                return -1;
            }
        } else if (matches(*argv, "linklayer") == 0) {
            NEXT_ARG();
            if (get_linklayer(&linklayer, *argv)) {
                explain1("linklayer");
                return -1;
            }
        } else if (matches(*argv, "help") == 0) {
            explain_class();
            return -1;
        } else {
            fprintf(stderr, "What is \"%s\"?\n", *argv);
            explain_class();
            return -1;
        }
        argc--;
        argv++;
    }

    /* OK. All options are parsed. */

    /* 1. Prepare link sharing scheduler parameters */
    if (r.rate) {
        unsigned pktsize = wrr.allot;
        if (wrr.allot < (lss.avpkt*3)/2)
            wrr.allot = (lss.avpkt*3)/2;
        r.mpu = mpu;
        r.overhead = overhead;
        if (tc_calc_rtable(&r, rtab, cell_log, pktsize, linklayer) < 0) {
            fprintf(stderr, "CBQ: failed to calculate rate table.\n");
            return -1;
        }
    }
    if (ewma_log < 0)
        ewma_log = TC_CBQ_DEF_EWMA;
    lss.ewma_log = ewma_log;
    if (lss.change&(TCF_CBQ_LSS_OFFTIME|TCF_CBQ_LSS_MAXIDLE)) {
        if (lss.avpkt == 0) {
            fprintf(stderr, "CBQ: avpkt is required for max/minburst.\n");
            return -1;
        }
        if (bndw==0 || r.rate == 0) {
            fprintf(stderr, "CBQ: bandwidth&rate are required for max/minburst.\n");
            return -1;
        }
    }
    if (wrr.priority == 0 && (n->nlmsg_flags&NLM_F_EXCL)) {
        wrr_ok = 1;
        wrr.priority = TC_CBQ_MAXPRIO;
        if (wrr.allot == 0)
            wrr.allot = (lss.avpkt*3)/2;
    }
    if (wrr_ok) {
        if (wrr.weight == 0)
            wrr.weight = (wrr.priority == TC_CBQ_MAXPRIO) ? 1 : r.rate;
        if (wrr.allot == 0) {
            fprintf(stderr, "CBQ: \"allot\" is required to set WRR parameters.\n");
            return -1;
        }
    }
    if (lss.change&TCF_CBQ_LSS_MAXIDLE) {
        lss.maxidle = tc_cbq_calc_maxidle(bndw, r.rate, lss.avpkt, ewma_log, maxburst);
        lss.change |= TCF_CBQ_LSS_MAXIDLE;
        lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
    }
    if (lss.change&TCF_CBQ_LSS_OFFTIME) {
        lss.offtime = tc_cbq_calc_offtime(bndw, r.rate, lss.avpkt, ewma_log, minburst);
        lss.change |= TCF_CBQ_LSS_OFFTIME;
        lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
    }
    if (lss.change&TCF_CBQ_LSS_MINIDLE) {
        lss.minidle <<= lss.ewma_log;
        lss.change |= TCF_CBQ_LSS_EWMA;
    }

    tail = NLMSG_TAIL(n);
    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
    if (lss.change) {
        lss.change |= TCF_CBQ_LSS_FLAGS;
        addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
    }
    if (wrr_ok)
        addattr_l(n, 1024, TCA_CBQ_WRROPT, &wrr, sizeof(wrr));
    if (fopt_ok)
        addattr_l(n, 1024, TCA_CBQ_FOPT, &fopt, sizeof(fopt));
    if (r.rate) {
        addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
        addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
        if (show_raw) {
            int i;
            for (i=0; i<256; i++)
                printf("%u ", rtab[i]);
            printf("\n");
        }
    }
    tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
    return 0;
}