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 <syslog.h> 20#include <fcntl.h> 21#include <sys/socket.h> 22#include <netinet/in.h> 23#include <arpa/inet.h> 24#include <string.h> 25 26#include "utils.h" 27#include "tc_util.h" 28 29struct action_util police_action_util = { 30 .id = "police", 31 .parse_aopt = act_parse_police, 32 .print_aopt = print_police, 33}; 34 35static void usage(void) 36{ 37 fprintf(stderr, "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n"); 38 fprintf(stderr, " [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n"); 39 fprintf(stderr, " [ linklayer TYPE ] [ ACTIONTERM ]\n"); 40 41 fprintf(stderr, "Old Syntax ACTIONTERM := action <EXCEEDACT>[/NOTEXCEEDACT] \n"); 42 fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT] \n"); 43 fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue \n"); 44 fprintf(stderr, "Where: pipe is only valid for new syntax \n"); 45 exit(-1); 46} 47 48static void explain1(char *arg) 49{ 50 fprintf(stderr, "Illegal \"%s\"\n", arg); 51} 52 53char *police_action_n2a(int action, char *buf, int len) 54{ 55 switch (action) { 56 case -1: 57 return "continue"; 58 break; 59 case TC_POLICE_OK: 60 return "pass"; 61 break; 62 case TC_POLICE_SHOT: 63 return "drop"; 64 break; 65 case TC_POLICE_RECLASSIFY: 66 return "reclassify"; 67 case TC_POLICE_PIPE: 68 return "pipe"; 69 default: 70 snprintf(buf, len, "%d", action); 71 return buf; 72 } 73} 74 75int police_action_a2n(char *arg, int *result) 76{ 77 int res; 78 79 if (matches(arg, "continue") == 0) 80 res = -1; 81 else if (matches(arg, "drop") == 0) 82 res = TC_POLICE_SHOT; 83 else if (matches(arg, "shot") == 0) 84 res = TC_POLICE_SHOT; 85 else if (matches(arg, "pass") == 0) 86 res = TC_POLICE_OK; 87 else if (strcmp(arg, "ok") == 0) 88 res = TC_POLICE_OK; 89 else if (matches(arg, "reclassify") == 0) 90 res = TC_POLICE_RECLASSIFY; 91 else if (matches(arg, "pipe") == 0) 92 res = TC_POLICE_PIPE; 93 else { 94 char dummy; 95 if (sscanf(arg, "%d%c", &res, &dummy) != 1) 96 return -1; 97 } 98 *result = res; 99 return 0; 100} 101 102 103int get_police_result(int *action, int *result, char *arg) 104{ 105 char *p = strchr(arg, '/'); 106 107 if (p) 108 *p = 0; 109 110 if (police_action_a2n(arg, action)) { 111 if (p) 112 *p = '/'; 113 return -1; 114 } 115 116 if (p) { 117 *p = '/'; 118 if (police_action_a2n(p+1, result)) 119 return -1; 120 } 121 return 0; 122} 123 124 125int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) 126{ 127 int argc = *argc_p; 128 char **argv = *argv_p; 129 int res = -1; 130 int ok=0; 131 struct tc_police p; 132 __u32 rtab[256]; 133 __u32 ptab[256]; 134 __u32 avrate = 0; 135 int presult = 0; 136 unsigned buffer=0, mtu=0, mpu=0; 137 unsigned short overhead=0; 138 unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ 139 int Rcell_log=-1, Pcell_log = -1; 140 struct rtattr *tail; 141 142 memset(&p, 0, sizeof(p)); 143 p.action = TC_POLICE_RECLASSIFY; 144 145 if (a) /* new way of doing things */ 146 NEXT_ARG(); 147 148 if (argc <= 0) 149 return -1; 150 151 while (argc > 0) { 152 153 if (matches(*argv, "index") == 0) { 154 NEXT_ARG(); 155 if (get_u32(&p.index, *argv, 10)) { 156 fprintf(stderr, "Illegal \"index\"\n"); 157 return -1; 158 } 159 } else if (matches(*argv, "burst") == 0 || 160 strcmp(*argv, "buffer") == 0 || 161 strcmp(*argv, "maxburst") == 0) { 162 NEXT_ARG(); 163 if (buffer) { 164 fprintf(stderr, "Double \"buffer/burst\" spec\n"); 165 return -1; 166 } 167 if (get_size_and_cell(&buffer, &Rcell_log, *argv) < 0) { 168 explain1("buffer"); 169 return -1; 170 } 171 } else if (strcmp(*argv, "mtu") == 0 || 172 strcmp(*argv, "minburst") == 0) { 173 NEXT_ARG(); 174 if (mtu) { 175 fprintf(stderr, "Double \"mtu/minburst\" spec\n"); 176 return -1; 177 } 178 if (get_size_and_cell(&mtu, &Pcell_log, *argv) < 0) { 179 explain1("mtu"); 180 return -1; 181 } 182 } else if (strcmp(*argv, "mpu") == 0) { 183 NEXT_ARG(); 184 if (mpu) { 185 fprintf(stderr, "Double \"mpu\" spec\n"); 186 return -1; 187 } 188 if (get_size(&mpu, *argv)) { 189 explain1("mpu"); 190 return -1; 191 } 192 } else if (strcmp(*argv, "rate") == 0) { 193 NEXT_ARG(); 194 if (p.rate.rate) { 195 fprintf(stderr, "Double \"rate\" spec\n"); 196 return -1; 197 } 198 if (get_rate(&p.rate.rate, *argv)) { 199 explain1("rate"); 200 return -1; 201 } 202 } else if (strcmp(*argv, "avrate") == 0) { 203 NEXT_ARG(); 204 if (avrate) { 205 fprintf(stderr, "Double \"avrate\" spec\n"); 206 return -1; 207 } 208 if (get_rate(&avrate, *argv)) { 209 explain1("avrate"); 210 return -1; 211 } 212 } else if (matches(*argv, "peakrate") == 0) { 213 NEXT_ARG(); 214 if (p.peakrate.rate) { 215 fprintf(stderr, "Double \"peakrate\" spec\n"); 216 return -1; 217 } 218 if (get_rate(&p.peakrate.rate, *argv)) { 219 explain1("peakrate"); 220 return -1; 221 } 222 } else if (matches(*argv, "reclassify") == 0) { 223 p.action = TC_POLICE_RECLASSIFY; 224 } else if (matches(*argv, "drop") == 0 || 225 matches(*argv, "shot") == 0) { 226 p.action = TC_POLICE_SHOT; 227 } else if (matches(*argv, "continue") == 0) { 228 p.action = TC_POLICE_UNSPEC; 229 } else if (matches(*argv, "pass") == 0) { 230 p.action = TC_POLICE_OK; 231 } else if (matches(*argv, "pipe") == 0) { 232 p.action = TC_POLICE_PIPE; 233 } else if (strcmp(*argv, "action") == 0 || 234 strcmp(*argv, "conform-exceed") == 0) { 235 NEXT_ARG(); 236 if (get_police_result(&p.action, &presult, *argv)) { 237 fprintf(stderr, "Illegal \"action\"\n"); 238 return -1; 239 } 240 } else if (matches(*argv, "overhead") == 0) { 241 NEXT_ARG(); 242 if (get_u16(&overhead, *argv, 10)) { 243 explain1("overhead"); return -1; 244 } 245 } else if (matches(*argv, "linklayer") == 0) { 246 NEXT_ARG(); 247 if (get_linklayer(&linklayer, *argv)) { 248 explain1("linklayer"); return -1; 249 } 250 } else if (strcmp(*argv, "help") == 0) { 251 usage(); 252 } else { 253 break; 254 } 255 ok++; 256 argc--; argv++; 257 } 258 259 if (!ok) 260 return -1; 261 262 if (p.rate.rate && !buffer) { 263 fprintf(stderr, "\"burst\" requires \"rate\".\n"); 264 return -1; 265 } 266 if (p.peakrate.rate) { 267 if (!p.rate.rate) { 268 fprintf(stderr, "\"peakrate\" requires \"rate\".\n"); 269 return -1; 270 } 271 if (!mtu) { 272 fprintf(stderr, "\"mtu\" is required, if \"peakrate\" is requested.\n"); 273 return -1; 274 } 275 } 276 277 if (p.rate.rate) { 278 p.rate.mpu = mpu; 279 p.rate.overhead = overhead; 280 if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, linklayer) < 0) { 281 fprintf(stderr, "TBF: failed to calculate rate table.\n"); 282 return -1; 283 } 284 p.burst = tc_calc_xmittime(p.rate.rate, buffer); 285 } 286 p.mtu = mtu; 287 if (p.peakrate.rate) { 288 p.peakrate.mpu = mpu; 289 p.peakrate.overhead = overhead; 290 if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) { 291 fprintf(stderr, "POLICE: failed to calculate peak rate table.\n"); 292 return -1; 293 } 294 } 295 296 tail = NLMSG_TAIL(n); 297 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 298 addattr_l(n, MAX_MSG, TCA_POLICE_TBF, &p, sizeof(p)); 299 if (p.rate.rate) 300 addattr_l(n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024); 301 if (p.peakrate.rate) 302 addattr_l(n, MAX_MSG, TCA_POLICE_PEAKRATE, ptab, 1024); 303 if (avrate) 304 addattr32(n, MAX_MSG, TCA_POLICE_AVRATE, avrate); 305 if (presult) 306 addattr32(n, MAX_MSG, TCA_POLICE_RESULT, presult); 307 308 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 309 res = 0; 310 311 *argc_p = argc; 312 *argv_p = argv; 313 return res; 314} 315 316int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) 317{ 318 return act_parse_police(NULL,argc_p,argv_p,tca_id,n); 319} 320 321int 322print_police(struct action_util *a, FILE *f, struct rtattr *arg) 323{ 324 SPRINT_BUF(b1); 325 struct tc_police *p; 326 struct rtattr *tb[TCA_POLICE_MAX+1]; 327 unsigned buffer; 328 329 if (arg == NULL) 330 return 0; 331 332 parse_rtattr_nested(tb, TCA_POLICE_MAX, arg); 333 334 if (tb[TCA_POLICE_TBF] == NULL) { 335 fprintf(f, "[NULL police tbf]"); 336 return 0; 337 } 338#ifndef STOOPID_8BYTE 339 if (RTA_PAYLOAD(tb[TCA_POLICE_TBF]) < sizeof(*p)) { 340 fprintf(f, "[truncated police tbf]"); 341 return -1; 342 } 343#endif 344 p = RTA_DATA(tb[TCA_POLICE_TBF]); 345 346 fprintf(f, " police 0x%x ", p->index); 347 fprintf(f, "rate %s ", sprint_rate(p->rate.rate, b1)); 348 buffer = tc_calc_xmitsize(p->rate.rate, p->burst); 349 fprintf(f, "burst %s ", sprint_size(buffer, b1)); 350 fprintf(f, "mtu %s ", sprint_size(p->mtu, b1)); 351 if (show_raw) 352 fprintf(f, "[%08x] ", p->burst); 353 if (p->peakrate.rate) 354 fprintf(f, "peakrate %s ", sprint_rate(p->peakrate.rate, b1)); 355 if (tb[TCA_POLICE_AVRATE]) 356 fprintf(f, "avrate %s ", sprint_rate(*(__u32*)RTA_DATA(tb[TCA_POLICE_AVRATE]), b1)); 357 fprintf(f, "action %s", police_action_n2a(p->action, b1, sizeof(b1))); 358 if (tb[TCA_POLICE_RESULT]) { 359 fprintf(f, "/%s ", police_action_n2a(*(int*)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); 360 } else 361 fprintf(f, " "); 362 fprintf(f, "overhead %ub ", p->rate.overhead); 363 fprintf(f, "\nref %d bind %d\n",p->refcnt, p->bindcnt); 364 365 return 0; 366} 367 368int 369tc_print_police(FILE *f, struct rtattr *arg) { 370 return print_police(&police_action_util,f,arg); 371} 372