2 * f_flower.c Flower Classifier
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.
9 * Authors: Jiri Pirko <jiri@resnulli.us>
18 #include <linux/if_ether.h>
25 static void explain(void)
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
, " eth_type [ipv4 | ipv6 | ETH-TYPE ] | \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");
48 static int flower_parse_eth_addr(char *str
, int addr_type
, int mask_type
,
54 ret
= ll_addr_a2n(addr
, sizeof(addr
), str
);
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
));
63 static int flower_parse_eth_type(char *str
, int type
, __be16
*p_eth_type
,
69 if (matches(str
, "ipv4") == 0) {
70 eth_type
= htons(ETH_P_IP
);
71 } else if (matches(str
, "ipv6") == 0) {
72 eth_type
= htons(ETH_P_IPV6
);
76 ret
= get_u16(&tmp
, str
, 16);
79 eth_type
= htons(tmp
);
81 addattr16(n
, MAX_MSG
, type
, eth_type
);
82 *p_eth_type
= eth_type
;
86 static int flower_parse_ip_proto(char *str
, __be16 eth_type
, int type
,
87 __u8
*p_ip_proto
, struct nlmsghdr
*n
)
92 if (eth_type
!= htons(ETH_P_IP
) && eth_type
!= htons(ETH_P_IPV6
)) {
93 fprintf(stderr
, "Illegal \"eth_type\" for ip proto\n");
96 if (matches(str
, "tcp") == 0) {
97 ip_proto
= IPPROTO_TCP
;
98 } else if (matches(str
, "udp") == 0) {
99 ip_proto
= IPPROTO_UDP
;
101 ret
= get_u8(&ip_proto
, str
, 16);
105 addattr8(n
, MAX_MSG
, type
, ip_proto
);
106 *p_ip_proto
= ip_proto
;
110 static int flower_parse_ip_addr(char *str
, __be16 eth_type
,
111 int addr4_type
, int mask4_type
,
112 int addr6_type
, int mask6_type
,
121 if (eth_type
== htons(ETH_P_IP
)) {
123 } else if (eth_type
== htons(ETH_P_IPV6
)) {
126 fprintf(stderr
, "Illegal \"eth_type\" for ip address\n");
130 ret
= get_prefix(&addr
, str
, family
);
134 if (addr
.family
!= family
)
137 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? addr4_type
: addr6_type
,
138 addr
.data
, addr
.bytelen
);
140 memset(addr
.data
, 0xff, addr
.bytelen
);
142 for (i
= 0; i
< addr
.bytelen
/ 4; i
++) {
145 } else if (bits
/ 32 >= 1) {
148 addr
.data
[i
] <<= 32 - bits
;
149 addr
.data
[i
] = htonl(addr
.data
[i
]);
154 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? mask4_type
: mask6_type
,
155 addr
.data
, addr
.bytelen
);
160 static int flower_parse_port(char *str
, __u8 ip_port
,
161 int tcp_type
, int udp_type
, struct nlmsghdr
*n
)
167 if (ip_port
== IPPROTO_TCP
) {
169 } else if (ip_port
== IPPROTO_UDP
) {
172 fprintf(stderr
, "Illegal \"ip_proto\" for port\n");
176 ret
= get_u16(&port
, str
, 10);
180 addattr16(n
, MAX_MSG
, type
, htons(port
));
185 static int flower_parse_opt(struct filter_util
*qu
, char *handle
,
186 int argc
, char **argv
, struct nlmsghdr
*n
)
189 struct tcmsg
*t
= NLMSG_DATA(n
);
192 __u8 ip_proto
= 0xff;
198 ret
= get_u32(&t
->tcm_handle
, handle
, 0);
200 fprintf(stderr
, "Illegal \"handle\"\n");
205 tail
= (struct rtattr
*) (((void *) n
) + NLMSG_ALIGN(n
->nlmsg_len
));
206 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
209 if (matches(*argv
, "classid") == 0 ||
210 matches(*argv
, "flowid") == 0) {
214 ret
= get_tc_classid(&handle
, *argv
);
216 fprintf(stderr
, "Illegal \"classid\"\n");
219 addattr_l(n
, MAX_MSG
, TCA_FLOWER_CLASSID
, &handle
, 4);
220 } else if (matches(*argv
, "indev") == 0) {
221 char ifname
[IFNAMSIZ
];
224 memset(ifname
, 0, sizeof(ifname
));
225 strncpy(ifname
, *argv
, sizeof(ifname
) - 1);
226 addattrstrz(n
, MAX_MSG
, TCA_FLOWER_INDEV
, ifname
);
227 } else if (matches(*argv
, "dst_mac") == 0) {
229 ret
= flower_parse_eth_addr(*argv
,
230 TCA_FLOWER_KEY_ETH_DST
,
231 TCA_FLOWER_KEY_ETH_DST_MASK
,
234 fprintf(stderr
, "Illegal \"dst_mac\"\n");
237 } else if (matches(*argv
, "src_mac") == 0) {
239 ret
= flower_parse_eth_addr(*argv
,
240 TCA_FLOWER_KEY_ETH_SRC
,
241 TCA_FLOWER_KEY_ETH_SRC_MASK
,
244 fprintf(stderr
, "Illegal \"src_mac\"\n");
247 } else if (matches(*argv
, "eth_type") == 0) {
249 ret
= flower_parse_eth_type(*argv
,
250 TCA_FLOWER_KEY_ETH_TYPE
,
253 fprintf(stderr
, "Illegal \"eth_type\"\n");
256 } else if (matches(*argv
, "ip_proto") == 0) {
258 ret
= flower_parse_ip_proto(*argv
, eth_type
,
259 TCA_FLOWER_KEY_IP_PROTO
,
262 fprintf(stderr
, "Illegal \"ip_proto\"\n");
265 } else if (matches(*argv
, "dst_ip") == 0) {
267 ret
= flower_parse_ip_addr(*argv
, eth_type
,
268 TCA_FLOWER_KEY_IPV4_DST
,
269 TCA_FLOWER_KEY_IPV4_DST_MASK
,
270 TCA_FLOWER_KEY_IPV6_DST
,
271 TCA_FLOWER_KEY_IPV6_DST_MASK
,
274 fprintf(stderr
, "Illegal \"dst_ip\"\n");
277 } else if (matches(*argv
, "src_ip") == 0) {
279 ret
= flower_parse_ip_addr(*argv
, eth_type
,
280 TCA_FLOWER_KEY_IPV4_SRC
,
281 TCA_FLOWER_KEY_IPV4_SRC_MASK
,
282 TCA_FLOWER_KEY_IPV6_SRC
,
283 TCA_FLOWER_KEY_IPV6_SRC_MASK
,
286 fprintf(stderr
, "Illegal \"src_ip\"\n");
289 } else if (matches(*argv
, "dst_port") == 0) {
291 ret
= flower_parse_port(*argv
, ip_proto
,
292 TCA_FLOWER_KEY_TCP_DST
,
293 TCA_FLOWER_KEY_UDP_DST
, n
);
295 fprintf(stderr
, "Illegal \"dst_port\"\n");
298 } else if (matches(*argv
, "src_port") == 0) {
300 ret
= flower_parse_port(*argv
, ip_proto
,
301 TCA_FLOWER_KEY_TCP_SRC
,
302 TCA_FLOWER_KEY_UDP_SRC
, n
);
304 fprintf(stderr
, "Illegal \"src_port\"\n");
307 } else if (matches(*argv
, "action") == 0) {
309 ret
= parse_action(&argc
, &argv
, TCA_FLOWER_ACT
, n
);
311 fprintf(stderr
, "Illegal \"action\"\n");
315 } else if (strcmp(*argv
, "help") == 0) {
319 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
326 tail
->rta_len
= (((void*)n
)+n
->nlmsg_len
) - (void*)tail
;
331 static int __mask_bits(char *addr
, size_t len
)
338 for (i
= 0; i
< len
; i
++, addr
++) {
339 for (j
= 7; j
>= 0; j
--) {
340 if (((*addr
) >> j
) & 0x1) {
354 static void flower_print_eth_addr(FILE *f
, char *name
,
355 struct rtattr
*addr_attr
,
356 struct rtattr
*mask_attr
)
361 if (!addr_attr
|| RTA_PAYLOAD(addr_attr
) != ETH_ALEN
)
363 fprintf(f
, "\n %s %s", name
, ll_addr_n2a(RTA_DATA(addr_attr
), ETH_ALEN
,
365 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != ETH_ALEN
)
367 bits
= __mask_bits(RTA_DATA(mask_attr
), ETH_ALEN
);
369 fprintf(f
, "/%s", ll_addr_n2a(RTA_DATA(mask_attr
), ETH_ALEN
,
371 else if (bits
< ETH_ALEN
* 8)
372 fprintf(f
, "/%d", bits
);
375 static void flower_print_eth_type(FILE *f
, __be16
*p_eth_type
,
376 struct rtattr
*eth_type_attr
)
383 eth_type
= rta_getattr_u16(eth_type_attr
);
384 fprintf(f
, "\n eth_type ");
385 if (eth_type
== htons(ETH_P_IP
))
387 else if (eth_type
== htons(ETH_P_IPV6
))
390 fprintf(f
, "%04x", ntohs(eth_type
));
391 *p_eth_type
= eth_type
;
394 static void flower_print_ip_proto(FILE *f
, __u8
*p_ip_proto
,
395 struct rtattr
*ip_proto_attr
)
402 ip_proto
= rta_getattr_u8(ip_proto_attr
);
403 fprintf(f
, "\n ip_proto ");
404 if (ip_proto
== IPPROTO_TCP
)
406 else if (ip_proto
== IPPROTO_UDP
)
409 fprintf(f
, "%02x", ip_proto
);
410 *p_ip_proto
= ip_proto
;
413 static void flower_print_ip_addr(FILE *f
, char *name
, __be16 eth_type
,
414 struct rtattr
*addr4_attr
,
415 struct rtattr
*mask4_attr
,
416 struct rtattr
*addr6_attr
,
417 struct rtattr
*mask6_attr
)
420 struct rtattr
*addr_attr
;
421 struct rtattr
*mask_attr
;
426 if (eth_type
== htons(ETH_P_IP
)) {
428 addr_attr
= addr4_attr
;
429 mask_attr
= mask4_attr
;
431 } else if (eth_type
== htons(ETH_P_IPV6
)) {
433 addr_attr
= addr6_attr
;
434 mask_attr
= mask6_attr
;
439 if (!addr_attr
|| RTA_PAYLOAD(addr_attr
) != len
)
441 fprintf(f
, "\n %s %s", name
, rt_addr_n2a(family
,
442 RTA_PAYLOAD(addr_attr
),
445 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != len
)
447 bits
= __mask_bits(RTA_DATA(mask_attr
), len
);
449 fprintf(f
, "/%s", rt_addr_n2a(family
,
450 RTA_PAYLOAD(mask_attr
),
453 else if (bits
< len
* 8)
454 fprintf(f
, "/%d", bits
);
457 static void flower_print_port(FILE *f
, char *name
, __u8 ip_proto
,
458 struct rtattr
*tcp_attr
,
459 struct rtattr
*udp_attr
)
463 if (ip_proto
== IPPROTO_TCP
)
465 else if (ip_proto
== IPPROTO_UDP
)
471 fprintf(f
, "\n %s %d", name
, ntohs(rta_getattr_u16(attr
)));
474 static int flower_print_opt(struct filter_util
*qu
, FILE *f
,
475 struct rtattr
*opt
, __u32 handle
)
477 struct rtattr
*tb
[TCA_FLOWER_MAX
+ 1];
479 __u8 ip_proto
= 0xff;
484 parse_rtattr_nested(tb
, TCA_FLOWER_MAX
, opt
);
487 fprintf(f
, "handle 0x%x ", handle
);
489 if (tb
[TCA_FLOWER_CLASSID
]) {
491 fprintf(f
, "classid %s ",
492 sprint_tc_classid(rta_getattr_u32(tb
[TCA_FLOWER_CLASSID
]), b1
));
495 if (tb
[TCA_FLOWER_INDEV
]) {
496 struct rtattr
*attr
= tb
[TCA_FLOWER_INDEV
];
498 fprintf(f
, "\n indev %s", rta_getattr_str(attr
));
501 flower_print_eth_addr(f
, "dst_mac", tb
[TCA_FLOWER_KEY_ETH_DST
],
502 tb
[TCA_FLOWER_KEY_ETH_DST_MASK
]);
503 flower_print_eth_addr(f
, "src_mac", tb
[TCA_FLOWER_KEY_ETH_SRC
],
504 tb
[TCA_FLOWER_KEY_ETH_SRC_MASK
]);
506 flower_print_eth_type(f
, ð_type
, tb
[TCA_FLOWER_KEY_ETH_TYPE
]);
507 flower_print_ip_proto(f
, &ip_proto
, tb
[TCA_FLOWER_KEY_IP_PROTO
]);
509 flower_print_ip_addr(f
, "dst_ip", eth_type
,
510 tb
[TCA_FLOWER_KEY_IPV4_DST
],
511 tb
[TCA_FLOWER_KEY_IPV4_DST_MASK
],
512 tb
[TCA_FLOWER_KEY_IPV6_DST
],
513 tb
[TCA_FLOWER_KEY_IPV6_DST_MASK
]);
515 flower_print_ip_addr(f
, "src_ip", eth_type
,
516 tb
[TCA_FLOWER_KEY_IPV4_SRC
],
517 tb
[TCA_FLOWER_KEY_IPV4_SRC_MASK
],
518 tb
[TCA_FLOWER_KEY_IPV6_SRC
],
519 tb
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]);
521 flower_print_port(f
, "dst_port", ip_proto
,
522 tb
[TCA_FLOWER_KEY_TCP_DST
],
523 tb
[TCA_FLOWER_KEY_UDP_DST
]);
525 flower_print_port(f
, "src_port", ip_proto
,
526 tb
[TCA_FLOWER_KEY_TCP_SRC
],
527 tb
[TCA_FLOWER_KEY_UDP_SRC
]);
529 if (tb
[TCA_FLOWER_ACT
]) {
530 tc_print_action(f
, tb
[TCA_FLOWER_ACT
]);
536 struct filter_util flower_filter_util
= {
538 .parse_fopt
= flower_parse_opt
,
539 .print_fopt
= flower_print_opt
,