1 /* 2 * f_flower.c Flower Classifier 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: Jiri Pirko <jiri (at) resnulli.us> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <syslog.h> 16 #include <string.h> 17 #include <net/if.h> 18 #include <linux/if_ether.h> 19 #include <linux/ip.h> 20 21 #include "utils.h" 22 #include "tc_util.h" 23 #include "rt_names.h" 24 25 static void explain(void) 26 { 27 fprintf(stderr, "Usage: ... flower [ MATCH-LIST ]\n"); 28 fprintf(stderr, " [ action ACTION-SPEC ] [ classid CLASSID ]\n"); 29 fprintf(stderr, "\n"); 30 fprintf(stderr, "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"); 31 fprintf(stderr, " MATCH := { indev DEV-NAME | \n"); 32 fprintf(stderr, " dst_mac MAC-ADDR | \n"); 33 fprintf(stderr, " src_mac MAC-ADDR | \n"); 34 fprintf(stderr, " [ipv4 | ipv6 ] | \n"); 35 fprintf(stderr, " ip_proto [tcp | udp | IP-PROTO ] | \n"); 36 fprintf(stderr, " dst_ip [ IPV4-ADDR | IPV6-ADDR ] | \n"); 37 fprintf(stderr, " src_ip [ IPV4-ADDR | IPV6-ADDR ] | \n"); 38 fprintf(stderr, " dst_port PORT-NUMBER | \n"); 39 fprintf(stderr, " src_port PORT-NUMBER }\n"); 40 fprintf(stderr, " FILTERID := X:Y:Z\n"); 41 fprintf(stderr, " ACTION-SPEC := ... look at individual actions\n"); 42 fprintf(stderr, "\n"); 43 fprintf(stderr, "NOTE: CLASSID, ETH-TYPE, IP-PROTO are parsed as hexadecimal input.\n"); 44 fprintf(stderr, "NOTE: There can be only used one mask per one prio. If user needs\n"); 45 fprintf(stderr, " to specify different mask, he has to use different prio.\n"); 46 } 47 48 static int flower_parse_eth_addr(char *str, int addr_type, int mask_type, 49 struct nlmsghdr *n) 50 { 51 int ret; 52 char addr[ETH_ALEN]; 53 54 ret = ll_addr_a2n(addr, sizeof(addr), str); 55 if (ret < 0) 56 return -1; 57 addattr_l(n, MAX_MSG, addr_type, addr, sizeof(addr)); 58 memset(addr, 0xff, ETH_ALEN); 59 addattr_l(n, MAX_MSG, mask_type, addr, sizeof(addr)); 60 return 0; 61 } 62 63 static int flower_parse_ip_proto(char *str, __be16 eth_type, int type, 64 __u8 *p_ip_proto, struct nlmsghdr *n) 65 { 66 int ret; 67 __u8 ip_proto; 68 69 if (eth_type != htons(ETH_P_IP) && eth_type != htons(ETH_P_IPV6)) { 70 fprintf(stderr, "Illegal \"eth_type\" for ip proto\n"); 71 return -1; 72 } 73 if (matches(str, "tcp") == 0) { 74 ip_proto = IPPROTO_TCP; 75 } else if (matches(str, "udp") == 0) { 76 ip_proto = IPPROTO_UDP; 77 } else { 78 ret = get_u8(&ip_proto, str, 16); 79 if (ret) 80 return -1; 81 } 82 addattr8(n, MAX_MSG, type, ip_proto); 83 *p_ip_proto = ip_proto; 84 return 0; 85 } 86 87 static int flower_parse_ip_addr(char *str, __be16 eth_type, 88 int addr4_type, int mask4_type, 89 int addr6_type, int mask6_type, 90 struct nlmsghdr *n) 91 { 92 int ret; 93 inet_prefix addr; 94 int family; 95 int bits; 96 int i; 97 98 if (eth_type == htons(ETH_P_IP)) { 99 family = AF_INET; 100 } else if (eth_type == htons(ETH_P_IPV6)) { 101 family = AF_INET6; 102 } else { 103 fprintf(stderr, "Illegal \"eth_type\" for ip address\n"); 104 return -1; 105 } 106 107 ret = get_prefix(&addr, str, family); 108 if (ret) 109 return -1; 110 111 if (addr.family != family) 112 return -1; 113 114 addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type, 115 addr.data, addr.bytelen); 116 117 memset(addr.data, 0xff, addr.bytelen); 118 bits = addr.bitlen; 119 for (i = 0; i < addr.bytelen / 4; i++) { 120 if (!bits) { 121 addr.data[i] = 0; 122 } else if (bits / 32 >= 1) { 123 bits -= 32; 124 } else { 125 addr.data[i] <<= 32 - bits; 126 addr.data[i] = htonl(addr.data[i]); 127 bits = 0; 128 } 129 } 130 131 addattr_l(n, MAX_MSG, addr.family == AF_INET ? mask4_type : mask6_type, 132 addr.data, addr.bytelen); 133 134 return 0; 135 } 136 137 static int flower_parse_port(char *str, __u8 ip_port, 138 int tcp_type, int udp_type, struct nlmsghdr *n) 139 { 140 int ret; 141 int type; 142 __be16 port; 143 144 if (ip_port == IPPROTO_TCP) { 145 type = tcp_type; 146 } else if (ip_port == IPPROTO_UDP) { 147 type = udp_type; 148 } else { 149 fprintf(stderr, "Illegal \"ip_proto\" for port\n"); 150 return -1; 151 } 152 153 ret = get_u16(&port, str, 10); 154 if (ret) 155 return -1; 156 157 addattr16(n, MAX_MSG, type, htons(port)); 158 159 return 0; 160 } 161 162 static int flower_parse_opt(struct filter_util *qu, char *handle, 163 int argc, char **argv, struct nlmsghdr *n) 164 { 165 int ret; 166 struct tcmsg *t = NLMSG_DATA(n); 167 struct rtattr *tail; 168 __be16 eth_type = TC_H_MIN(t->tcm_info); 169 __u8 ip_proto = 0xff; 170 171 if (handle) { 172 ret = get_u32(&t->tcm_handle, handle, 0); 173 if (ret) { 174 fprintf(stderr, "Illegal \"handle\"\n"); 175 return -1; 176 } 177 } 178 179 tail = (struct rtattr *) (((void *) n) + NLMSG_ALIGN(n->nlmsg_len)); 180 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); 181 182 if (argc == 0) { 183 /*at minimal we will match all ethertype packets */ 184 goto parse_done; 185 } 186 187 while (argc > 0) { 188 if (matches(*argv, "classid") == 0 || 189 matches(*argv, "flowid") == 0) { 190 unsigned handle; 191 192 NEXT_ARG(); 193 ret = get_tc_classid(&handle, *argv); 194 if (ret) { 195 fprintf(stderr, "Illegal \"classid\"\n"); 196 return -1; 197 } 198 addattr_l(n, MAX_MSG, TCA_FLOWER_CLASSID, &handle, 4); 199 } else if (matches(*argv, "indev") == 0) { 200 char ifname[IFNAMSIZ]; 201 202 NEXT_ARG(); 203 memset(ifname, 0, sizeof(ifname)); 204 strncpy(ifname, *argv, sizeof(ifname) - 1); 205 addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, ifname); 206 } else if (matches(*argv, "dst_mac") == 0) { 207 NEXT_ARG(); 208 ret = flower_parse_eth_addr(*argv, 209 TCA_FLOWER_KEY_ETH_DST, 210 TCA_FLOWER_KEY_ETH_DST_MASK, 211 n); 212 if (ret < 0) { 213 fprintf(stderr, "Illegal \"dst_mac\"\n"); 214 return -1; 215 } 216 } else if (matches(*argv, "src_mac") == 0) { 217 NEXT_ARG(); 218 ret = flower_parse_eth_addr(*argv, 219 TCA_FLOWER_KEY_ETH_SRC, 220 TCA_FLOWER_KEY_ETH_SRC_MASK, 221 n); 222 if (ret < 0) { 223 fprintf(stderr, "Illegal \"src_mac\"\n"); 224 return -1; 225 } 226 } else if (matches(*argv, "ip_proto") == 0) { 227 NEXT_ARG(); 228 ret = flower_parse_ip_proto(*argv, eth_type, 229 TCA_FLOWER_KEY_IP_PROTO, 230 &ip_proto, n); 231 if (ret < 0) { 232 fprintf(stderr, "Illegal \"ip_proto\"\n"); 233 return -1; 234 } 235 } else if (matches(*argv, "dst_ip") == 0) { 236 NEXT_ARG(); 237 ret = flower_parse_ip_addr(*argv, eth_type, 238 TCA_FLOWER_KEY_IPV4_DST, 239 TCA_FLOWER_KEY_IPV4_DST_MASK, 240 TCA_FLOWER_KEY_IPV6_DST, 241 TCA_FLOWER_KEY_IPV6_DST_MASK, 242 n); 243 if (ret < 0) { 244 fprintf(stderr, "Illegal \"dst_ip\"\n"); 245 return -1; 246 } 247 } else if (matches(*argv, "src_ip") == 0) { 248 NEXT_ARG(); 249 ret = flower_parse_ip_addr(*argv, eth_type, 250 TCA_FLOWER_KEY_IPV4_SRC, 251 TCA_FLOWER_KEY_IPV4_SRC_MASK, 252 TCA_FLOWER_KEY_IPV6_SRC, 253 TCA_FLOWER_KEY_IPV6_SRC_MASK, 254 n); 255 if (ret < 0) { 256 fprintf(stderr, "Illegal \"src_ip\"\n"); 257 return -1; 258 } 259 } else if (matches(*argv, "dst_port") == 0) { 260 NEXT_ARG(); 261 ret = flower_parse_port(*argv, ip_proto, 262 TCA_FLOWER_KEY_TCP_DST, 263 TCA_FLOWER_KEY_UDP_DST, n); 264 if (ret < 0) { 265 fprintf(stderr, "Illegal \"dst_port\"\n"); 266 return -1; 267 } 268 } else if (matches(*argv, "src_port") == 0) { 269 NEXT_ARG(); 270 ret = flower_parse_port(*argv, ip_proto, 271 TCA_FLOWER_KEY_TCP_SRC, 272 TCA_FLOWER_KEY_UDP_SRC, n); 273 if (ret < 0) { 274 fprintf(stderr, "Illegal \"src_port\"\n"); 275 return -1; 276 } 277 } else if (matches(*argv, "action") == 0) { 278 NEXT_ARG(); 279 ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n); 280 if (ret) { 281 fprintf(stderr, "Illegal \"action\"\n"); 282 return -1; 283 } 284 continue; 285 } else if (strcmp(*argv, "help") == 0) { 286 explain(); 287 return -1; 288 } else { 289 fprintf(stderr, "What is \"%s\"?\n", *argv); 290 explain(); 291 return -1; 292 } 293 argc--; argv++; 294 } 295 296 parse_done: 297 ret = addattr16(n, MAX_MSG, TCA_FLOWER_KEY_ETH_TYPE, eth_type); 298 if (ret) { 299 fprintf(stderr, "Illegal \"eth_type\"(0x%x)\n", 300 ntohs(eth_type)); 301 return -1; 302 } 303 304 tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail; 305 306 return 0; 307 } 308 309 static int __mask_bits(char *addr, size_t len) 310 { 311 int bits = 0; 312 bool hole = false; 313 int i; 314 int j; 315 316 for (i = 0; i < len; i++, addr++) { 317 for (j = 7; j >= 0; j--) { 318 if (((*addr) >> j) & 0x1) { 319 if (hole) 320 return -1; 321 bits++; 322 } else if (bits) { 323 hole = true; 324 } else{ 325 return -1; 326 } 327 } 328 } 329 return bits; 330 } 331 332 static void flower_print_eth_addr(FILE *f, char *name, 333 struct rtattr *addr_attr, 334 struct rtattr *mask_attr) 335 { 336 SPRINT_BUF(b1); 337 int bits; 338 339 if (!addr_attr || RTA_PAYLOAD(addr_attr) != ETH_ALEN) 340 return; 341 fprintf(f, "\n %s %s", name, ll_addr_n2a(RTA_DATA(addr_attr), ETH_ALEN, 342 0, b1, sizeof(b1))); 343 if (!mask_attr || RTA_PAYLOAD(mask_attr) != ETH_ALEN) 344 return; 345 bits = __mask_bits(RTA_DATA(mask_attr), ETH_ALEN); 346 if (bits < 0) 347 fprintf(f, "/%s", ll_addr_n2a(RTA_DATA(mask_attr), ETH_ALEN, 348 0, b1, sizeof(b1))); 349 else if (bits < ETH_ALEN * 8) 350 fprintf(f, "/%d", bits); 351 } 352 353 static void flower_print_eth_type(FILE *f, __be16 *p_eth_type, 354 struct rtattr *eth_type_attr) 355 { 356 __be16 eth_type; 357 358 if (!eth_type_attr) 359 return; 360 361 eth_type = rta_getattr_u16(eth_type_attr); 362 fprintf(f, "\n eth_type "); 363 if (eth_type == htons(ETH_P_IP)) 364 fprintf(f, "ipv4"); 365 else if (eth_type == htons(ETH_P_IPV6)) 366 fprintf(f, "ipv6"); 367 else 368 fprintf(f, "%04x", ntohs(eth_type)); 369 *p_eth_type = eth_type; 370 } 371 372 static void flower_print_ip_proto(FILE *f, __u8 *p_ip_proto, 373 struct rtattr *ip_proto_attr) 374 { 375 __u8 ip_proto; 376 377 if (!ip_proto_attr) 378 return; 379 380 ip_proto = rta_getattr_u8(ip_proto_attr); 381 fprintf(f, "\n ip_proto "); 382 if (ip_proto == IPPROTO_TCP) 383 fprintf(f, "tcp"); 384 else if (ip_proto == IPPROTO_UDP) 385 fprintf(f, "udp"); 386 else 387 fprintf(f, "%02x", ip_proto); 388 *p_ip_proto = ip_proto; 389 } 390 391 static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, 392 struct rtattr *addr4_attr, 393 struct rtattr *mask4_attr, 394 struct rtattr *addr6_attr, 395 struct rtattr *mask6_attr) 396 { 397 SPRINT_BUF(b1); 398 struct rtattr *addr_attr; 399 struct rtattr *mask_attr; 400 int family; 401 size_t len; 402 int bits; 403 404 if (eth_type == htons(ETH_P_IP)) { 405 family = AF_INET; 406 addr_attr = addr4_attr; 407 mask_attr = mask4_attr; 408 len = 4; 409 } else if (eth_type == htons(ETH_P_IPV6)) { 410 family = AF_INET6; 411 addr_attr = addr6_attr; 412 mask_attr = mask6_attr; 413 len = 16; 414 } else { 415 return; 416 } 417 if (!addr_attr || RTA_PAYLOAD(addr_attr) != len) 418 return; 419 fprintf(f, "\n %s %s", name, rt_addr_n2a(family, 420 RTA_PAYLOAD(addr_attr), 421 RTA_DATA(addr_attr), 422 b1, sizeof(b1))); 423 if (!mask_attr || RTA_PAYLOAD(mask_attr) != len) 424 return; 425 bits = __mask_bits(RTA_DATA(mask_attr), len); 426 if (bits < 0) 427 fprintf(f, "/%s", rt_addr_n2a(family, 428 RTA_PAYLOAD(mask_attr), 429 RTA_DATA(mask_attr), 430 b1, sizeof(b1))); 431 else if (bits < len * 8) 432 fprintf(f, "/%d", bits); 433 } 434 435 static void flower_print_port(FILE *f, char *name, __u8 ip_proto, 436 struct rtattr *tcp_attr, 437 struct rtattr *udp_attr) 438 { 439 struct rtattr *attr; 440 441 if (ip_proto == IPPROTO_TCP) 442 attr = tcp_attr; 443 else if (ip_proto == IPPROTO_UDP) 444 attr = udp_attr; 445 else 446 return; 447 if (!attr) 448 return; 449 fprintf(f, "\n %s %d", name, ntohs(rta_getattr_u16(attr))); 450 } 451 452 static int flower_print_opt(struct filter_util *qu, FILE *f, 453 struct rtattr *opt, __u32 handle) 454 { 455 struct rtattr *tb[TCA_FLOWER_MAX + 1]; 456 __be16 eth_type = 0; 457 __u8 ip_proto = 0xff; 458 459 if (!opt) 460 return 0; 461 462 parse_rtattr_nested(tb, TCA_FLOWER_MAX, opt); 463 464 if (handle) 465 fprintf(f, "handle 0x%x ", handle); 466 467 if (tb[TCA_FLOWER_CLASSID]) { 468 SPRINT_BUF(b1); 469 fprintf(f, "classid %s ", 470 sprint_tc_classid(rta_getattr_u32(tb[TCA_FLOWER_CLASSID]), 471 b1)); 472 } 473 474 if (tb[TCA_FLOWER_INDEV]) { 475 struct rtattr *attr = tb[TCA_FLOWER_INDEV]; 476 477 fprintf(f, "\n indev %s", rta_getattr_str(attr)); 478 } 479 480 flower_print_eth_addr(f, "dst_mac", tb[TCA_FLOWER_KEY_ETH_DST], 481 tb[TCA_FLOWER_KEY_ETH_DST_MASK]); 482 flower_print_eth_addr(f, "src_mac", tb[TCA_FLOWER_KEY_ETH_SRC], 483 tb[TCA_FLOWER_KEY_ETH_SRC_MASK]); 484 485 flower_print_eth_type(f, ð_type, tb[TCA_FLOWER_KEY_ETH_TYPE]); 486 flower_print_ip_proto(f, &ip_proto, tb[TCA_FLOWER_KEY_IP_PROTO]); 487 488 flower_print_ip_addr(f, "dst_ip", eth_type, 489 tb[TCA_FLOWER_KEY_IPV4_DST], 490 tb[TCA_FLOWER_KEY_IPV4_DST_MASK], 491 tb[TCA_FLOWER_KEY_IPV6_DST], 492 tb[TCA_FLOWER_KEY_IPV6_DST_MASK]); 493 494 flower_print_ip_addr(f, "src_ip", eth_type, 495 tb[TCA_FLOWER_KEY_IPV4_SRC], 496 tb[TCA_FLOWER_KEY_IPV4_SRC_MASK], 497 tb[TCA_FLOWER_KEY_IPV6_SRC], 498 tb[TCA_FLOWER_KEY_IPV6_SRC_MASK]); 499 500 flower_print_port(f, "dst_port", ip_proto, 501 tb[TCA_FLOWER_KEY_TCP_DST], 502 tb[TCA_FLOWER_KEY_UDP_DST]); 503 504 flower_print_port(f, "src_port", ip_proto, 505 tb[TCA_FLOWER_KEY_TCP_SRC], 506 tb[TCA_FLOWER_KEY_UDP_SRC]); 507 508 if (tb[TCA_FLOWER_ACT]) { 509 tc_print_action(f, tb[TCA_FLOWER_ACT]); 510 } 511 512 return 0; 513 } 514 515 struct filter_util flower_filter_util = { 516 .id = "flower", 517 .parse_fopt = flower_parse_opt, 518 .print_fopt = flower_print_opt, 519 }; 520