iproute2/tc/m_police.c
<<
>>
Prefs
   1/*
   2 * m_police.c           Parse/print policing module options.
   3 *
   4 *              This program is free software; you can u32istribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  10 * FIXES:       19990619 - J Hadi Salim (hadi@cyberus.ca)
  11 *              simple addattr packaging fix.
  12 *              2002: J Hadi Salim - Add tc action extensions syntax
  13 *
  14 */
  15
  16#include <stdio.h>
  17#include <stdlib.h>
  18#include <unistd.h>
  19#include <fcntl.h>
  20#include <sys/socket.h>
  21#include <netinet/in.h>
  22#include <arpa/inet.h>
  23#include <string.h>
  24
  25#include "utils.h"
  26#include "tc_util.h"
  27
  28static int act_parse_police(struct action_util *a, int *argc_p,
  29                            char ***argv_p, int tca_id, struct nlmsghdr *n);
  30static int print_police(struct action_util *a, FILE *f, struct rtattr *tb);
  31
  32struct action_util police_action_util = {
  33        .id = "police",
  34        .parse_aopt = act_parse_police,
  35        .print_aopt = print_police,
  36};
  37
  38static void usage(void)
  39{
  40        fprintf(stderr,
  41                "Usage: ... police [ rate BPS burst BYTES[/BYTES] ] \n"
  42                "               [ pkts_rate RATE pkts_burst PACKETS ] [ mtu BYTES[/BYTES] ]\n"
  43                "               [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n"
  44                "               [ linklayer TYPE ] [ CONTROL ]\n"
  45                "Where: CONTROL := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT]\n"
  46                "                 Define how to handle packets which exceed (<EXCEEDACT>)\n"
  47                "                 or conform (<NOTEXCEEDACT>) the configured bandwidth limit.\n"
  48                "       EXCEEDACT/NOTEXCEEDACT := { pipe | ok | reclassify | drop | continue |\n"
  49                "                                  goto chain <CHAIN_INDEX> }\n");
  50        exit(-1);
  51}
  52
  53static int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p,
  54                            int tca_id, struct nlmsghdr *n)
  55{
  56        int argc = *argc_p;
  57        char **argv = *argv_p;
  58        int res = -1;
  59        int ok = 0;
  60        struct tc_police p = { .action = TC_POLICE_RECLASSIFY };
  61        __u32 rtab[256];
  62        __u32 ptab[256];
  63        __u32 avrate = 0;
  64        int presult = 0;
  65        unsigned buffer = 0, mtu = 0, mpu = 0;
  66        unsigned short overhead = 0;
  67        unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
  68        int Rcell_log =  -1, Pcell_log = -1;
  69        struct rtattr *tail;
  70        __u64 rate64 = 0, prate64 = 0;
  71        __u64 pps64 = 0, ppsburst64 = 0;
  72
  73        if (a) /* new way of doing things */
  74                NEXT_ARG();
  75
  76        if (argc <= 0)
  77                return -1;
  78
  79        while (argc > 0) {
  80
  81                if (matches(*argv, "index") == 0) {
  82                        NEXT_ARG();
  83                        if (get_u32(&p.index, *argv, 10))
  84                                invarg("index", *argv);
  85                } else if (matches(*argv, "burst") == 0 ||
  86                        strcmp(*argv, "buffer") == 0 ||
  87                        strcmp(*argv, "maxburst") == 0) {
  88                        NEXT_ARG();
  89                        if (buffer)
  90                                duparg("buffer/burst", *argv);
  91                        if (get_size_and_cell(&buffer, &Rcell_log, *argv) < 0)
  92                                invarg("buffer", *argv);
  93                } else if (strcmp(*argv, "mtu") == 0 ||
  94                           strcmp(*argv, "minburst") == 0) {
  95                        NEXT_ARG();
  96                        if (mtu)
  97                                duparg("mtu/minburst", *argv);
  98                        if (get_size_and_cell(&mtu, &Pcell_log, *argv) < 0)
  99                                invarg("mtu", *argv);
 100                } else if (strcmp(*argv, "mpu") == 0) {
 101                        NEXT_ARG();
 102                        if (mpu)
 103                                duparg("mpu", *argv);
 104                        if (get_size(&mpu, *argv))
 105                                invarg("mpu", *argv);
 106                } else if (strcmp(*argv, "rate") == 0) {
 107                        NEXT_ARG();
 108                        if (rate64)
 109                                duparg("rate", *argv);
 110                        if (get_rate64(&rate64, *argv))
 111                                invarg("rate", *argv);
 112                } else if (strcmp(*argv, "avrate") == 0) {
 113                        NEXT_ARG();
 114                        if (avrate)
 115                                duparg("avrate", *argv);
 116                        if (get_rate(&avrate, *argv))
 117                                invarg("avrate", *argv);
 118                } else if (matches(*argv, "peakrate") == 0) {
 119                        NEXT_ARG();
 120                        if (prate64)
 121                                duparg("peakrate", *argv);
 122                        if (get_rate64(&prate64, *argv))
 123                                invarg("peakrate", *argv);
 124                } else if (matches(*argv, "reclassify") == 0 ||
 125                           matches(*argv, "drop") == 0 ||
 126                           matches(*argv, "shot") == 0 ||
 127                           matches(*argv, "continue") == 0 ||
 128                           matches(*argv, "pass") == 0 ||
 129                           matches(*argv, "ok") == 0 ||
 130                           matches(*argv, "pipe") == 0 ||
 131                           matches(*argv, "goto") == 0) {
 132                        if (!parse_action_control(&argc, &argv, &p.action, false))
 133                                goto action_ctrl_ok;
 134                        return -1;
 135                } else if (strcmp(*argv, "conform-exceed") == 0) {
 136                        NEXT_ARG();
 137                        if (!parse_action_control_slash(&argc, &argv, &p.action,
 138                                                        &presult, true))
 139                                goto action_ctrl_ok;
 140                        return -1;
 141                } else if (matches(*argv, "overhead") == 0) {
 142                        NEXT_ARG();
 143                        if (get_u16(&overhead, *argv, 10))
 144                                invarg("overhead", *argv);
 145                } else if (matches(*argv, "linklayer") == 0) {
 146                        NEXT_ARG();
 147                        if (get_linklayer(&linklayer, *argv))
 148                                invarg("linklayer", *argv);
 149                } else if (matches(*argv, "pkts_rate") == 0) {
 150                        NEXT_ARG();
 151                        if (pps64)
 152                                duparg("pkts_rate", *argv);
 153                        if (get_u64(&pps64, *argv, 10))
 154                                invarg("pkts_rate", *argv);
 155                } else if (matches(*argv, "pkts_burst") == 0) {
 156                        NEXT_ARG();
 157                        if (ppsburst64)
 158                                duparg("pkts_burst", *argv);
 159                        if (get_u64(&ppsburst64, *argv, 10))
 160                                invarg("pkts_burst", *argv);
 161                } else if (strcmp(*argv, "help") == 0) {
 162                        usage();
 163                } else {
 164                        break;
 165                }
 166                NEXT_ARG_FWD();
 167action_ctrl_ok:
 168                ok++;
 169        }
 170
 171        if (!ok)
 172                return -1;
 173
 174        if (rate64 && avrate)
 175                return -1;
 176
 177        /* Must at least do late binding, use TB or ewma policing */
 178        if (!rate64 && !avrate && !p.index && !mtu && !pps64) {
 179                fprintf(stderr, "'rate' or 'avrate' or 'mtu' or 'pkts_rate' MUST be specified.\n");
 180                return -1;
 181        }
 182
 183        /* When the TB policer is used, burst is required */
 184        if (rate64 && !buffer && !avrate) {
 185                fprintf(stderr, "'burst' requires 'rate'.\n");
 186                return -1;
 187        }
 188
 189        /* When the packets TB policer is used, pkts_burst is required */
 190        if (pps64 && !ppsburst64) {
 191                fprintf(stderr, "'pkts_burst' requires 'pkts_rate'.\n");
 192                return -1;
 193        }
 194
 195        /* forbid rate and pkts_rate in same action */
 196        if (pps64 && rate64) {
 197                fprintf(stderr, "'rate' and 'pkts_rate' are not allowed in same action.\n");
 198                return -1;
 199        }
 200
 201        if (prate64) {
 202                if (!rate64) {
 203                        fprintf(stderr, "'peakrate' requires 'rate'.\n");
 204                        return -1;
 205                }
 206                if (!mtu) {
 207                        fprintf(stderr, "'mtu' is required, if 'peakrate' is requested.\n");
 208                        return -1;
 209                }
 210        }
 211
 212        if (rate64) {
 213                p.rate.rate = (rate64 >= (1ULL << 32)) ? ~0U : rate64;
 214                p.rate.mpu = mpu;
 215                p.rate.overhead = overhead;
 216                if (tc_calc_rtable_64(&p.rate, rtab, Rcell_log, mtu,
 217                                   linklayer, rate64) < 0) {
 218                        fprintf(stderr, "POLICE: failed to calculate rate table.\n");
 219                        return -1;
 220                }
 221                p.burst = tc_calc_xmittime(rate64, buffer);
 222        }
 223        p.mtu = mtu;
 224        if (prate64) {
 225                p.peakrate.rate = (prate64 >= (1ULL << 32)) ? ~0U : prate64;
 226                p.peakrate.mpu = mpu;
 227                p.peakrate.overhead = overhead;
 228                if (tc_calc_rtable_64(&p.peakrate, ptab, Pcell_log, mtu,
 229                                   linklayer, prate64) < 0) {
 230                        fprintf(stderr, "POLICE: failed to calculate peak rate table.\n");
 231                        return -1;
 232                }
 233        }
 234
 235        tail = addattr_nest(n, MAX_MSG, tca_id);
 236        addattr_l(n, MAX_MSG, TCA_POLICE_TBF, &p, sizeof(p));
 237        if (rate64) {
 238                addattr_l(n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024);
 239                if (rate64 >= (1ULL << 32))
 240                        addattr64(n, MAX_MSG, TCA_POLICE_RATE64, rate64);
 241        }
 242        if (prate64) {
 243                addattr_l(n, MAX_MSG, TCA_POLICE_PEAKRATE, ptab, 1024);
 244                if (prate64 >= (1ULL << 32))
 245                        addattr64(n, MAX_MSG, TCA_POLICE_PEAKRATE64, prate64);
 246        }
 247        if (avrate)
 248                addattr32(n, MAX_MSG, TCA_POLICE_AVRATE, avrate);
 249        if (presult)
 250                addattr32(n, MAX_MSG, TCA_POLICE_RESULT, presult);
 251
 252        if (pps64) {
 253                addattr64(n, MAX_MSG, TCA_POLICE_PKTRATE64, pps64);
 254                ppsburst64 = tc_calc_xmittime(pps64, ppsburst64);
 255                addattr64(n, MAX_MSG, TCA_POLICE_PKTBURST64, ppsburst64);
 256        }
 257
 258        addattr_nest_end(n, tail);
 259        res = 0;
 260
 261        *argc_p = argc;
 262        *argv_p = argv;
 263        return res;
 264}
 265
 266int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
 267{
 268        return act_parse_police(NULL, argc_p, argv_p, tca_id, n);
 269}
 270
 271static int print_police(struct action_util *a, FILE *f, struct rtattr *arg)
 272{
 273        SPRINT_BUF(b2);
 274        struct tc_police *p;
 275        struct rtattr *tb[TCA_POLICE_MAX+1];
 276        unsigned int buffer;
 277        unsigned int linklayer;
 278        __u64 rate64, prate64;
 279        __u64 pps64, ppsburst64;
 280
 281        print_string(PRINT_JSON, "kind", "%s", "police");
 282        if (arg == NULL)
 283                return 0;
 284
 285        parse_rtattr_nested(tb, TCA_POLICE_MAX, arg);
 286
 287        if (tb[TCA_POLICE_TBF] == NULL) {
 288                fprintf(stderr, "[NULL police tbf]");
 289                return -1;
 290        }
 291#ifndef STOOPID_8BYTE
 292        if (RTA_PAYLOAD(tb[TCA_POLICE_TBF])  < sizeof(*p)) {
 293                fprintf(stderr, "[truncated police tbf]");
 294                return -1;
 295        }
 296#endif
 297        p = RTA_DATA(tb[TCA_POLICE_TBF]);
 298
 299        rate64 = p->rate.rate;
 300        if (tb[TCA_POLICE_RATE64] &&
 301            RTA_PAYLOAD(tb[TCA_POLICE_RATE64]) >= sizeof(rate64))
 302                rate64 = rta_getattr_u64(tb[TCA_POLICE_RATE64]);
 303
 304        print_hex(PRINT_FP, NULL, " police 0x%x ", p->index);
 305        print_uint(PRINT_JSON, "index", NULL, p->index);
 306        tc_print_rate(PRINT_FP, NULL, "rate %s ", rate64);
 307        buffer = tc_calc_xmitsize(rate64, p->burst);
 308        print_size(PRINT_FP, NULL, "burst %s ", buffer);
 309        print_size(PRINT_FP, NULL, "mtu %s ", p->mtu);
 310        if (show_raw)
 311                print_hex(PRINT_FP, NULL, "[%08x] ", p->burst);
 312
 313        prate64 = p->peakrate.rate;
 314        if (tb[TCA_POLICE_PEAKRATE64] &&
 315            RTA_PAYLOAD(tb[TCA_POLICE_PEAKRATE64]) >= sizeof(prate64))
 316                prate64 = rta_getattr_u64(tb[TCA_POLICE_PEAKRATE64]);
 317
 318        if (prate64)
 319                tc_print_rate(PRINT_FP, NULL, "peakrate %s ", prate64);
 320
 321        if (tb[TCA_POLICE_AVRATE])
 322                tc_print_rate(PRINT_FP, NULL, "avrate %s ",
 323                              rta_getattr_u32(tb[TCA_POLICE_AVRATE]));
 324
 325        if ((tb[TCA_POLICE_PKTRATE64] &&
 326             RTA_PAYLOAD(tb[TCA_POLICE_PKTRATE64]) >= sizeof(pps64)) &&
 327             (tb[TCA_POLICE_PKTBURST64] &&
 328              RTA_PAYLOAD(tb[TCA_POLICE_PKTBURST64]) >= sizeof(ppsburst64))) {
 329                pps64 = rta_getattr_u64(tb[TCA_POLICE_PKTRATE64]);
 330                ppsburst64 = rta_getattr_u64(tb[TCA_POLICE_PKTBURST64]);
 331                ppsburst64 = tc_calc_xmitsize(pps64, ppsburst64);
 332                print_u64(PRINT_ANY, "pkts_rate", "pkts_rate %llu ", pps64);
 333                print_u64(PRINT_ANY, "pkts_burst", "pkts_burst %llu ", ppsburst64);
 334        }
 335
 336        print_action_control(f, "action ", p->action, "");
 337
 338        if (tb[TCA_POLICE_RESULT]) {
 339                __u32 action = rta_getattr_u32(tb[TCA_POLICE_RESULT]);
 340
 341                print_action_control(f, "/", action, " ");
 342        } else {
 343                print_string(PRINT_FP, NULL, " ", NULL);
 344        }
 345
 346        print_size(PRINT_ANY, "overhead", "overhead %s ", p->rate.overhead);
 347        linklayer = (p->rate.linklayer & TC_LINKLAYER_MASK);
 348        if (linklayer > TC_LINKLAYER_ETHERNET || show_details)
 349                print_string(PRINT_ANY, "linklayer", "linklayer %s ",
 350                             sprint_linklayer(linklayer, b2));
 351        print_nl();
 352        print_int(PRINT_ANY, "ref", "\tref %d ", p->refcnt);
 353        print_int(PRINT_ANY, "bind", "bind %d ", p->bindcnt);
 354        if (show_stats) {
 355                if (tb[TCA_POLICE_TM]) {
 356                        struct tcf_t *tm = RTA_DATA(tb[TCA_POLICE_TM]);
 357
 358                        print_tm(f, tm);
 359                }
 360        }
 361        print_nl();
 362
 363
 364        return 0;
 365}
 366
 367int tc_print_police(FILE *f, struct rtattr *arg)
 368{
 369        return print_police(&police_action_util, f, arg);
 370}
 371