Home | History | Annotate | Download | only in tc
      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, &eth_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