12#include <netlink-private/netlink.h> 
   13#include <netlink-private/tc.h> 
   14#include <netlink/netlink.h> 
   15#include <netlink/cache.h> 
   16#include <netlink/utils.h> 
   17#include <netlink-private/route/tc-api.h> 
   18#include <netlink/route/qdisc.h> 
   19#include <netlink/route/class.h> 
   20#include <netlink/route/link.h> 
   21#include <netlink/route/qdisc/tbf.h> 
   24#define TBF_ATTR_LIMIT                  0x01 
   25#define TBF_ATTR_RATE                   0x02 
   26#define TBF_ATTR_PEAKRATE               0x10 
   29static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
 
   30        [TCA_TBF_PARMS] = { .
minlen = 
sizeof(
struct tc_tbf_qopt) },
 
   33static int tbf_msg_parser(
struct rtnl_tc *tc, 
void *data)
 
   35        struct nlattr *tb[TCA_TBF_MAX + 1];
 
   36        struct rtnl_tbf *tbf = data;
 
   39        if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0)
 
   42        if (tb[TCA_TBF_PARMS]) {
 
   43                struct tc_tbf_qopt opts;
 
   46                nla_memcpy(&opts, tb[TCA_TBF_PARMS], 
sizeof(opts));
 
   47                tbf->qt_limit = opts.limit;
 
   49                rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
 
   50                tbf->qt_rate_txtime = opts.buffer;
 
   51                bufsize = rtnl_tc_calc_bufsize64(
nl_ticks2us(opts.buffer),
 
   52                                                 tbf->qt_rate.rs_rate64);
 
   53                tbf->qt_rate_bucket = bufsize;
 
   55                rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
 
   56                tbf->qt_peakrate_txtime = opts.mtu;
 
   57                bufsize = rtnl_tc_calc_bufsize64(
nl_ticks2us(opts.mtu),
 
   58                                                 tbf->qt_peakrate.rs_rate64);
 
   59                tbf->qt_peakrate_bucket = bufsize;
 
   64                tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE);
 
   70static void tbf_dump_line(
struct rtnl_tc *tc, 
void *data,
 
   74        char *ru, *rubit, *limu;
 
   75        struct rtnl_tbf *tbf = data;
 
   84        nl_dump(p, 
" rate %.2f%s/s (%.0f%s) limit %.2f%s",
 
   85                r, ru, rbit, rubit, lim, limu);
 
   88static void tbf_dump_details(
struct rtnl_tc *tc, 
void *data,
 
   91        struct rtnl_tbf *tbf = data;
 
  102                nl_dump(p, 
"rate-bucket-size %1.f%s " 
  103                           "rate-cell-size %.1f%s\n",
 
  108        if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
 
  109                char *pru, *prbu, *bsu, *clu;
 
  110                double pr, prb, bs, cl;
 
  119                             "    peak-rate %.2f%s/s (%.0f%s) " 
  120                             "bucket-size %.1f%s cell-size %.1f%s",
 
  121                             pr, pru, prb, prbu, bs, bsu, cl, clu);
 
  125static int tbf_msg_fill(
struct rtnl_tc *tc, 
void *data, 
struct nl_msg *msg)
 
  127        uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE];
 
  128        struct tc_tbf_qopt opts;
 
  129        struct rtnl_tbf *tbf = data;
 
  130        int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
 
  132        if ((tbf->qt_mask & required) != required)
 
  133                return -NLE_MISSING_ATTR;
 
  135        memset(&opts, 0, 
sizeof(opts));
 
  136        opts.limit = tbf->qt_limit;
 
  137        opts.buffer = tbf->qt_rate_txtime;
 
  140        rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
 
  142        if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
 
  143                opts.mtu = tbf->qt_peakrate_txtime;
 
  145                rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
 
  149        NLA_PUT(msg, TCA_TBF_PARMS, 
sizeof(opts), &opts);
 
  150        NLA_PUT(msg, TCA_TBF_RTAB, 
sizeof(rtab), rtab);
 
  152        if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
 
  153                NLA_PUT(msg, TCA_TBF_PTAB, 
sizeof(ptab), ptab);
 
  174        struct rtnl_tbf *tbf;
 
  179        tbf->qt_limit = limit;
 
  180        tbf->qt_mask |= TBF_ATTR_LIMIT;
 
  183static inline double calc_limit(
struct rtnl_ratespec *spec, 
int latency,
 
  188        limit = (double) spec->rs_rate64 * ((
double) latency / 1000000.);
 
  214        struct rtnl_tbf *tbf;
 
  215        double limit, limit2;
 
  220        if (!(tbf->qt_mask & TBF_ATTR_RATE))
 
  221                return -NLE_MISSING_ATTR;
 
  223        limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
 
  225        if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
 
  226                limit2 = calc_limit(&tbf->qt_peakrate, latency,
 
  227                                    tbf->qt_peakrate_bucket);
 
  245        struct rtnl_tbf *tbf;
 
  250        if (tbf->qt_mask & TBF_ATTR_LIMIT)
 
  251                return tbf->qt_limit;
 
  256static inline int calc_cell_log(
int cell, 
int bucket)
 
  273        struct rtnl_tbf *tbf;
 
  280                cell_log = UINT8_MAX;
 
  284        tbf->qt_rate.rs_rate64 = (uint32_t)rate;
 
  285        tbf->qt_rate_bucket = bucket;
 
  286        tbf->qt_rate.rs_cell_log = cell_log;
 
  287        tbf->qt_rate_txtime = 
nl_us2ticks(rtnl_tc_calc_txtime64(bucket, tbf->qt_rate.rs_rate64));
 
  288        tbf->qt_mask |= TBF_ATTR_RATE;
 
  298        struct rtnl_tbf *tbf;
 
  303        if (tbf->qt_mask & TBF_ATTR_RATE)
 
  304                return tbf->qt_rate.rs_rate64;
 
  316        struct rtnl_tbf *tbf;
 
  321        if (tbf->qt_mask & TBF_ATTR_RATE)
 
  322                return tbf->qt_rate_bucket;
 
  334        struct rtnl_tbf *tbf;
 
  339        if (tbf->qt_mask & TBF_ATTR_RATE)
 
  340                return (1 << tbf->qt_rate.rs_cell_log);
 
  356        struct rtnl_tbf *tbf;
 
  362        cell_log = calc_cell_log(cell, bucket);
 
  366        tbf->qt_peakrate.rs_rate64 = (uint32_t)rate;
 
  367        tbf->qt_peakrate_bucket = bucket;
 
  368        tbf->qt_peakrate.rs_cell_log = cell_log;
 
  369        tbf->qt_peakrate_txtime = 
nl_us2ticks(rtnl_tc_calc_txtime64(bucket, tbf->qt_peakrate.rs_rate64));
 
  371        tbf->qt_mask |= TBF_ATTR_PEAKRATE;
 
  383        struct rtnl_tbf *tbf;
 
  388        if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
 
  389                return tbf->qt_peakrate.rs_rate64;
 
  401        struct rtnl_tbf *tbf;
 
  406        if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
 
  407                return tbf->qt_peakrate_bucket;
 
  419        struct rtnl_tbf *tbf;
 
  424        if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
 
  425                return (1 << tbf->qt_peakrate.rs_cell_log);
 
  432static struct rtnl_tc_ops tbf_tc_ops = {
 
  434        .to_type                = RTNL_TC_TYPE_QDISC,
 
  435        .to_size                = 
sizeof(
struct rtnl_tbf),
 
  436        .to_msg_parser          = tbf_msg_parser,
 
  441        .to_msg_fill            = tbf_msg_fill,
 
  444static void __init tbf_init(
void)
 
  449static void __exit tbf_exit(
void)
 
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
 
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
 
int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
Set limit of TBF qdisc by latency.
 
int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
Get rate of TBF qdisc.
 
int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
Get peak rate bucket size of TBF qdisc.
 
int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
Get rate cell size of TBF qdisc.
 
int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
Get rate bucket size of TBF qdisc.
 
void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
Set limit of TBF qdisc.
 
int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
Get limit of TBF qdisc.
 
int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, int cell)
Set peak rate of TBF qdisc.
 
int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
Get peak rate cell size of TBF qdisc.
 
void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, int cell)
Set rate of TBF qdisc.
 
int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
Get peak rate of TBF qdisc.
 
void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu)
Set the Minimum Packet Unit (MPU) of a traffic control object.
 
int rtnl_tc_calc_cell_log(int cell_size)
Calculate the binary logarithm for a specific cell size.
 
int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec, uint32_t *dst)
Compute a transmission time lookup table.
 
void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead)
Set per packet overhead of a traffic control object.
 
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
 
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
 
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
 
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
 
double nl_cancel_down_bits(unsigned long long l, char **unit)
Cancel down a bit counter.
 
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
 
double nl_cancel_down_bytes(unsigned long long l, char **unit)
Cancel down a byte counter.
 
uint32_t nl_ticks2us(uint32_t ticks)
Convert ticks to micro seconds.
 
uint32_t nl_us2ticks(uint32_t us)
Convert micro seconds to ticks.
 
@ NL_DUMP_LINE
Dump object briefly on one line.
 
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
 
Attribute validation policy.
 
uint16_t minlen
Minimal length of payload required.