em_meta.c revision 311b41454dc445639924c691a949bd15fbfab0cb
1/* 2 * em_meta.c Metadata Ematch 3 * 4 * This program is free software; you can distribute 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: Thomas Graf <tgraf@suug.ch> 10 */ 11 12#include <stdio.h> 13#include <stdlib.h> 14#include <unistd.h> 15#include <syslog.h> 16#include <fcntl.h> 17#include <sys/socket.h> 18#include <netinet/in.h> 19#include <arpa/inet.h> 20#include <string.h> 21#include <dlfcn.h> 22#include <errno.h> 23 24#include "m_ematch.h" 25#include <linux/tc_ematch/tc_em_meta.h> 26 27extern struct ematch_util meta_ematch_util; 28 29static void meta_print_usage(FILE *fd) 30{ 31 fprintf(fd, 32 "Usage: meta(OBJECT { eq | lt | gt } OBJECT)\n" \ 33 "where: OBJECT := { META_ID | VALUE }\n" \ 34 " META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \ 35 "\n" \ 36 "Example: meta(nfmark gt 24)\n" \ 37 " meta(indev shift 1 eq \"ppp\"\n" \ 38 " meta(tcindex mask 0xf0 eq 0xf0)\n" \ 39 " meta(dev eq indev)\n" \ 40 "\n" \ 41 "For a list of meta identifiers, use meta(list).\n"); 42} 43 44struct meta_entry { 45 int id; 46 char * kind; 47 char * mask; 48 char * desc; 49} meta_table[] = { 50#define TCF_META_ID_SECTION 0 51#define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc } 52 __A(SECTION, "Generic", "", ""), 53 __A(RANDOM, "random", "i", 54 "Random value (32 bit)"), 55 __A(LOADAVG_0, "loadavg_1", "i", 56 "Load average in last minute"), 57 __A(LOADAVG_1, "loadavg_5", "i", 58 "Load average in last 5 minutes"), 59 __A(LOADAVG_2, "loadavg_15", "i", 60 "Load average in last 15 minutes"), 61 62 __A(SECTION, "Interfaces", "", ""), 63 __A(DEV, "dev", "iv", 64 "Device the packet is on"), 65 __A(INDEV, "indev", "iv", 66 "Device the packet came in"), 67 __A(REALDEV, "realdev", "iv", 68 "Underlying real device"), 69 70 __A(SECTION, "Packet attributes", "", ""), 71 __A(PRIORITY, "priority", "i", 72 "Priority of packet"), 73 __A(PROTOCOL, "protocol", "i", 74 "Link layer protocol"), 75 __A(SECURITY, "security", "i", 76 "Security level"), 77 __A(PKTTYPE, "pkt_type", "i", 78 "Packet type (uni|multi|broad|...)cast"), 79 __A(PKTLEN, "pkt_len", "i", 80 "Length of packet"), 81 __A(DATALEN, "data_len", "i", 82 "Length of data in packet"), 83 __A(MACLEN, "mac_len", "i", 84 "Length of link layer header"), 85 86 __A(SECTION, "Netfilter", "", ""), 87 __A(NFMARK, "nf_mark", "i", 88 "Netfilter mark"), 89 __A(NFMARK, "fwmark", "i", 90 "Alias for nf_mark"), 91 92 __A(SECTION, "Traffic Control", "", ""), 93 __A(TCINDEX, "tc_index", "i", "TC Index"), 94 __A(TCVERDICT, "tc_verdict", "i", "TC Verdict"), 95 __A(TCCLASSID, "tc_classid", "i", "TC ClassID"), 96 97 __A(SECTION, "Routing", "", ""), 98 __A(RTCLASSID, "rt_classid", "i", 99 "Routing ClassID (cls_route)"), 100 __A(RTIIF, "rt_iif", "i", 101 "Incoming interface index"), 102 103 __A(SECTION, "Sockets", "", ""), 104 __A(SK_FAMILY, "sk_family", "i", "Address family"), 105 __A(SK_STATE, "sk_state", "i", "State"), 106 __A(SK_REUSE, "sk_reuse", "i", "Reuse Flag"), 107 __A(SK_BOUND_IF, "sk_bind_if", "iv", "Bound interface"), 108 __A(SK_REFCNT, "sk_refcnt", "i", "Reference counter"), 109 __A(SK_SHUTDOWN, "sk_shutdown", "i", "Shutdown mask"), 110 __A(SK_PROTO, "sk_proto", "i", "Protocol"), 111 __A(SK_TYPE, "sk_type", "i", "Type"), 112 __A(SK_RCVBUF, "sk_rcvbuf", "i", "Receive buffer size"), 113 __A(SK_RMEM_ALLOC, "sk_rmem", "i", "RMEM"), 114 __A(SK_WMEM_ALLOC, "sk_wmem", "i", "WMEM"), 115 __A(SK_OMEM_ALLOC, "sk_omem", "i", "OMEM"), 116 __A(SK_WMEM_QUEUED, "sk_wmem_queue","i", "WMEM queue"), 117 __A(SK_SND_QLEN, "sk_snd_queue", "i", "Send queue length"), 118 __A(SK_RCV_QLEN, "sk_rcv_queue", "i", "Receive queue length"), 119 __A(SK_ERR_QLEN, "sk_err_queue", "i", "Error queue length"), 120 __A(SK_FORWARD_ALLOCS, "sk_fwd_alloc", "i", "Forward allocations"), 121 __A(SK_SNDBUF, "sk_sndbuf", "i", "Send buffer size"), 122#undef __A 123}; 124 125static inline int map_type(char k) 126{ 127 switch (k) { 128 case 'i': return TCF_META_TYPE_INT; 129 case 'v': return TCF_META_TYPE_VAR; 130 } 131 132 fprintf(stderr, "BUG: Unknown map character '%c'\n", k); 133 return INT_MAX; 134} 135 136static struct meta_entry * lookup_meta_entry(struct bstr *kind) 137{ 138 int i; 139 140 for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) 141 if (!bstrcmp(kind, meta_table[i].kind) && 142 meta_table[i].id != 0) 143 return &meta_table[i]; 144 145 return NULL; 146} 147 148static struct meta_entry * lookup_meta_entry_byid(int id) 149{ 150 int i; 151 152 for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) 153 if (meta_table[i].id == id) 154 return &meta_table[i]; 155 156 return NULL; 157} 158 159static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val, 160 struct tcf_meta_val *hdr) 161{ 162 __u32 t; 163 164 switch (TCF_META_TYPE(hdr->kind)) { 165 case TCF_META_TYPE_INT: 166 t = val; 167 addattr_l(n, MAX_MSG, tlv, &t, sizeof(t)); 168 break; 169 170 case TCF_META_TYPE_VAR: 171 if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) { 172 struct bstr *a = (struct bstr *) val; 173 addattr_l(n, MAX_MSG, tlv, a->data, a->len); 174 } 175 break; 176 } 177} 178 179static inline int is_compatible(struct tcf_meta_val *what, 180 struct tcf_meta_val *needed) 181{ 182 char *p; 183 struct meta_entry *entry; 184 185 entry = lookup_meta_entry_byid(TCF_META_ID(what->kind)); 186 187 if (entry == NULL) 188 return 0; 189 190 for (p = entry->mask; p; p++) 191 if (map_type(*p) == TCF_META_TYPE(needed->kind)) 192 return 1; 193 194 return 0; 195} 196 197static void list_meta_ids(FILE *fd) 198{ 199 int i; 200 201 fprintf(fd, 202 "--------------------------------------------------------\n" \ 203 " ID Type Description\n" \ 204 "--------------------------------------------------------"); 205 206 for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) { 207 if (meta_table[i].id == TCF_META_ID_SECTION) { 208 fprintf(fd, "\n%s:\n", meta_table[i].kind); 209 } else { 210 char *p = meta_table[i].mask; 211 char buf[64] = {0}; 212 213 fprintf(fd, " %-16s ", meta_table[i].kind); 214 215 while (*p) { 216 int type = map_type(*p); 217 218 switch (type) { 219 case TCF_META_TYPE_INT: 220 strcat(buf, "INT"); 221 break; 222 223 case TCF_META_TYPE_VAR: 224 strcat(buf, "VAR"); 225 break; 226 } 227 228 if (*(++p)) 229 strcat(buf, ","); 230 } 231 232 fprintf(fd, "%-10s %s\n", buf, meta_table[i].desc); 233 } 234 } 235 236 fprintf(fd, 237 "--------------------------------------------------------\n"); 238} 239 240#undef TCF_META_ID_SECTION 241 242#define PARSE_FAILURE ((void *) (-1)) 243 244#define PARSE_ERR(CARG, FMT, ARGS...) \ 245 em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT ,##ARGS) 246 247static inline int can_adopt(struct tcf_meta_val *val) 248{ 249 return !!TCF_META_ID(val->kind); 250} 251 252static inline int overwrite_type(struct tcf_meta_val *src, 253 struct tcf_meta_val *dst) 254{ 255 return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind); 256} 257 258 259static inline struct bstr * 260parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj, 261 unsigned long *dst, struct tcf_meta_val *left) 262{ 263 struct meta_entry *entry; 264 unsigned long num; 265 struct bstr *a; 266 267 if (arg->quoted) { 268 obj->kind = TCF_META_TYPE_VAR << 12; 269 obj->kind |= TCF_META_ID_VALUE; 270 *dst = (unsigned long) arg; 271 return bstr_next(arg); 272 } 273 274 num = bstrtoul(arg); 275 if (num != LONG_MAX) { 276 obj->kind = TCF_META_TYPE_INT << 12; 277 obj->kind |= TCF_META_ID_VALUE; 278 *dst = (unsigned long) num; 279 return bstr_next(arg); 280 } 281 282 entry = lookup_meta_entry(arg); 283 284 if (entry == NULL) { 285 PARSE_ERR(arg, "meta: unknown meta id\n"); 286 return PARSE_FAILURE; 287 } 288 289 obj->kind = entry->id | (map_type(entry->mask[0]) << 12); 290 291 if (left) { 292 struct tcf_meta_val *right = obj; 293 294 if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind)) 295 goto compatible; 296 297 if (can_adopt(left) && !can_adopt(right)) { 298 if (is_compatible(left, right)) 299 left->kind = overwrite_type(left, right); 300 else 301 goto not_compatible; 302 } else if (can_adopt(right) && !can_adopt(left)) { 303 if (is_compatible(right, left)) 304 right->kind = overwrite_type(right, left); 305 else 306 goto not_compatible; 307 } else if (can_adopt(left) && can_adopt(right)) { 308 if (is_compatible(left, right)) 309 left->kind = overwrite_type(left, right); 310 else if (is_compatible(right, left)) 311 right->kind = overwrite_type(right, left); 312 else 313 goto not_compatible; 314 } else 315 goto not_compatible; 316 } 317 318compatible: 319 320 a = bstr_next(arg); 321 322 while(a) { 323 if (!bstrcmp(a, "shift")) { 324 unsigned long shift; 325 326 if (a->next == NULL) { 327 PARSE_ERR(a, "meta: missing argument"); 328 return PARSE_FAILURE; 329 } 330 a = bstr_next(a); 331 332 shift = bstrtoul(a); 333 if (shift == LONG_MAX) { 334 PARSE_ERR(a, "meta: invalid shift, must " \ 335 "be numeric"); 336 return PARSE_FAILURE; 337 } 338 339 obj->shift = (__u8) shift; 340 a = bstr_next(a); 341 } else if (!bstrcmp(a, "mask")) { 342 unsigned long mask; 343 344 if (a->next == NULL) { 345 PARSE_ERR(a, "meta: missing argument"); 346 return PARSE_FAILURE; 347 } 348 a = bstr_next(a); 349 350 mask = bstrtoul(a); 351 if (mask == LONG_MAX) { 352 PARSE_ERR(a, "meta: invalid mask, must be " \ 353 "numeric"); 354 return PARSE_FAILURE; 355 } 356 *dst = (unsigned long) mask; 357 a = bstr_next(a); 358 } else 359 break; 360 } 361 362 return a; 363 364not_compatible: 365 PARSE_ERR(arg, "lvalue and rvalue are not compatible."); 366 return PARSE_FAILURE; 367} 368 369static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, 370 struct bstr *args) 371{ 372 int opnd; 373 struct bstr *a; 374 struct tcf_meta_hdr meta_hdr; 375 unsigned long lvalue = 0, rvalue = 0; 376 377 memset(&meta_hdr, 0, sizeof(meta_hdr)); 378 379 if (args == NULL) 380 return PARSE_ERR(args, "meta: missing arguments"); 381 382 if (!bstrcmp(args, "list")) { 383 list_meta_ids(stderr); 384 return -1; 385 } 386 387 a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL); 388 if (a == PARSE_FAILURE) 389 return -1; 390 else if (a == NULL) 391 return PARSE_ERR(args, "meta: missing operand"); 392 393 if (!bstrcmp(a, "eq")) 394 opnd = TCF_EM_OPND_EQ; 395 else if (!bstrcmp(a, "gt")) 396 opnd = TCF_EM_OPND_GT; 397 else if (!bstrcmp(a, "lt")) 398 opnd = TCF_EM_OPND_LT; 399 else 400 return PARSE_ERR(a, "meta: invalid operand"); 401 402 meta_hdr.left.op = (__u8) opnd; 403 404 if (a->next == NULL) 405 return PARSE_ERR(args, "meta: missing rvalue"); 406 a = bstr_next(a); 407 408 a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left); 409 if (a == PARSE_FAILURE) 410 return -1; 411 else if (a != NULL) 412 return PARSE_ERR(a, "meta: unexpected trailer"); 413 414 415 addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); 416 417 addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr)); 418 419 if (lvalue) 420 dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left); 421 422 if (rvalue) 423 dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right); 424 425 return 0; 426} 427#undef PARSE_ERR 428 429static inline void print_binary(FILE *fd, unsigned char *str, int len) 430{ 431 int i; 432 433 for (i = 0; i < len; i++) 434 if (!isprint(str[i])) 435 goto binary; 436 437 for (i = 0; i < len; i++) 438 fprintf(fd, "%c", str[i]); 439 return; 440 441binary: 442 for (i = 0; i < len; i++) 443 fprintf(fd, "%02x ", str[i]); 444 445 fprintf(fd, "\""); 446 for (i = 0; i < len; i++) 447 fprintf(fd, "%c", isprint(str[i]) ? str[i] : '.'); 448 fprintf(fd, "\""); 449} 450 451static inline int print_value(FILE *fd, int type, struct rtattr *rta) 452{ 453 if (rta == NULL) { 454 fprintf(stderr, "Missing value TLV\n"); 455 return -1; 456 } 457 458 switch(type) { 459 case TCF_META_TYPE_INT: 460 if (RTA_PAYLOAD(rta) < sizeof(__u32)) { 461 fprintf(stderr, "meta int type value TLV " \ 462 "size mismatch.\n"); 463 return -1; 464 } 465 fprintf(fd, "%d", *(__u32 *) RTA_DATA(rta)); 466 break; 467 468 case TCF_META_TYPE_VAR: 469 print_binary(fd, RTA_DATA(rta), RTA_PAYLOAD(rta)); 470 break; 471 } 472 473 return 0; 474} 475 476static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta) 477{ 478 int id = TCF_META_ID(obj->kind); 479 int type = TCF_META_TYPE(obj->kind); 480 struct meta_entry *entry; 481 482 if (id == TCF_META_ID_VALUE) 483 return print_value(fd, type, rta); 484 485 entry = lookup_meta_entry_byid(id); 486 487 if (entry == NULL) 488 fprintf(fd, "[unknown meta id %d]", id); 489 else 490 fprintf(fd, "%s", entry->kind); 491 492 if (obj->shift) 493 fprintf(fd, " shift %d", obj->shift); 494 495 switch (type) { 496 case TCF_META_TYPE_INT: 497 if (rta) { 498 if (RTA_PAYLOAD(rta) < sizeof(__u32)) 499 goto size_mismatch; 500 501 fprintf(fd, " mask 0x%08x", 502 *(__u32*) RTA_DATA(rta)); 503 } 504 break; 505 } 506 507 return 0; 508 509size_mismatch: 510 fprintf(stderr, "meta int type mask TLV size mismatch\n"); 511 return -1; 512} 513 514 515static int meta_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, 516 int data_len) 517{ 518 struct rtattr *tb[TCA_EM_META_MAX+1]; 519 struct tcf_meta_hdr *meta_hdr; 520 521 if (parse_rtattr(tb, TCA_EM_META_MAX, data, data_len) < 0) 522 return -1; 523 524 if (tb[TCA_EM_META_HDR] == NULL) { 525 fprintf(stderr, "Missing meta header\n"); 526 return -1; 527 } 528 529 if (RTA_PAYLOAD(tb[TCA_EM_META_HDR]) < sizeof(*meta_hdr)) { 530 fprintf(stderr, "Meta header size mismatch\n"); 531 return -1; 532 } 533 534 meta_hdr = RTA_DATA(tb[TCA_EM_META_HDR]); 535 536 if (print_object(fd, &meta_hdr->left, tb[TCA_EM_META_LVALUE]) < 0) 537 return -1; 538 539 switch (meta_hdr->left.op) { 540 case TCF_EM_OPND_EQ: 541 fprintf(fd, " eq "); 542 break; 543 case TCF_EM_OPND_LT: 544 fprintf(fd, " lt "); 545 break; 546 case TCF_EM_OPND_GT: 547 fprintf(fd, " gt "); 548 break; 549 } 550 551 return print_object(fd, &meta_hdr->right, tb[TCA_EM_META_RVALUE]); 552} 553 554struct ematch_util meta_ematch_util = { 555 .kind = "meta", 556 .kind_num = TCF_EM_META, 557 .parse_eopt = meta_parse_eopt, 558 .print_eopt = meta_print_eopt, 559 .print_usage = meta_print_usage 560}; 561