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>
20 #include <linux/tc_act/tc_vlan.h>
26 enum flower_endpoint
{
31 enum flower_icmp_field
{
32 FLOWER_ICMP_FIELD_TYPE
,
33 FLOWER_ICMP_FIELD_CODE
36 static void explain(void)
39 "Usage: ... flower [ MATCH-LIST ]\n"
40 " [ skip_sw | skip_hw ]\n"
41 " [ action ACTION-SPEC ] [ classid CLASSID ]\n"
43 "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"
44 " MATCH := { indev DEV-NAME |\n"
46 " vlan_prio PRIORITY |\n"
47 " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
48 " dst_mac MASKED-LLADDR |\n"
49 " src_mac MASKED-LLADDR |\n"
50 " ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
53 " dst_port PORT-NUMBER |\n"
54 " src_port PORT-NUMBER |\n"
57 " enc_dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
58 " enc_src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
59 " enc_key_id [ KEY-ID ] |\n"
60 " matching_flags MATCHING-FLAGS | \n"
61 " enc_dst_port [ UDP-PORT ] }\n"
62 " FILTERID := X:Y:Z\n"
63 " MASKED_LLADDR := { LLADDR | LLADDR/MASK | LLADDR/BITS }\n"
64 " ACTION-SPEC := ... look at individual actions\n"
66 "NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n"
67 "NOTE: There can be only used one mask per one prio. If user needs\n"
68 " to specify different mask, he has to use different prio.\n");
71 static int flower_parse_eth_addr(char *str
, int addr_type
, int mask_type
,
75 char addr
[ETH_ALEN
], *slash
;
77 slash
= strchr(str
, '/');
81 ret
= ll_addr_a2n(addr
, sizeof(addr
), str
);
84 addattr_l(n
, MAX_MSG
, addr_type
, addr
, sizeof(addr
));
89 if (!get_unsigned(&bits
, slash
+ 1, 10)) {
92 /* Extra 16 bit shift to push mac address into
93 * high bits of uint64_t
95 mask
= htonll(0xffffffffffffULL
<< (16 + 48 - bits
));
96 memcpy(addr
, &mask
, ETH_ALEN
);
98 ret
= ll_addr_a2n(addr
, sizeof(addr
), slash
+ 1);
103 memset(addr
, 0xff, ETH_ALEN
);
105 addattr_l(n
, MAX_MSG
, mask_type
, addr
, sizeof(addr
));
114 static int flower_parse_vlan_eth_type(char *str
, __be16 eth_type
, int type
,
115 __be16
*p_vlan_eth_type
,
118 __be16 vlan_eth_type
;
120 if (eth_type
!= htons(ETH_P_8021Q
)) {
122 "Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n");
126 if (ll_proto_a2n(&vlan_eth_type
, str
))
127 invarg("invalid vlan_ethtype", str
);
128 addattr16(n
, MAX_MSG
, type
, vlan_eth_type
);
129 *p_vlan_eth_type
= vlan_eth_type
;
133 static int flower_parse_matching_flags(char *str
, int type
, int mask_type
,
139 c
= strchr(str
, '/');
143 if (get_u32(&mtf
, str
, 0))
147 if (get_u32(&mtf_mask
, ++c
, 0))
150 mtf_mask
= 0xffffffff;
153 addattr32(n
, MAX_MSG
, type
, htonl(mtf
));
154 addattr32(n
, MAX_MSG
, mask_type
, htonl(mtf_mask
));
158 static int flower_parse_ip_proto(char *str
, __be16 eth_type
, int type
,
159 __u8
*p_ip_proto
, struct nlmsghdr
*n
)
164 if (eth_type
!= htons(ETH_P_IP
) && eth_type
!= htons(ETH_P_IPV6
))
167 if (matches(str
, "tcp") == 0) {
168 ip_proto
= IPPROTO_TCP
;
169 } else if (matches(str
, "udp") == 0) {
170 ip_proto
= IPPROTO_UDP
;
171 } else if (matches(str
, "sctp") == 0) {
172 ip_proto
= IPPROTO_SCTP
;
173 } else if (matches(str
, "icmp") == 0) {
174 if (eth_type
!= htons(ETH_P_IP
))
176 ip_proto
= IPPROTO_ICMP
;
177 } else if (matches(str
, "icmpv6") == 0) {
178 if (eth_type
!= htons(ETH_P_IPV6
))
180 ip_proto
= IPPROTO_ICMPV6
;
182 ret
= get_u8(&ip_proto
, str
, 16);
186 addattr8(n
, MAX_MSG
, type
, ip_proto
);
187 *p_ip_proto
= ip_proto
;
191 fprintf(stderr
, "Illegal \"eth_type\" for ip proto\n");
195 static int flower_parse_ip_addr(char *str
, __be16 eth_type
,
196 int addr4_type
, int mask4_type
,
197 int addr6_type
, int mask6_type
,
206 if (eth_type
== htons(ETH_P_IP
)) {
208 } else if (eth_type
== htons(ETH_P_IPV6
)) {
210 } else if (!eth_type
) {
216 ret
= get_prefix(&addr
, str
, family
);
220 if (family
&& (addr
.family
!= family
)) {
221 fprintf(stderr
, "Illegal \"eth_type\" for ip address\n");
225 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? addr4_type
: addr6_type
,
226 addr
.data
, addr
.bytelen
);
228 memset(addr
.data
, 0xff, addr
.bytelen
);
230 for (i
= 0; i
< addr
.bytelen
/ 4; i
++) {
233 } else if (bits
/ 32 >= 1) {
236 addr
.data
[i
] <<= 32 - bits
;
237 addr
.data
[i
] = htonl(addr
.data
[i
]);
242 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? mask4_type
: mask6_type
,
243 addr
.data
, addr
.bytelen
);
248 static int flower_icmp_attr_type(__be16 eth_type
, __u8 ip_proto
,
249 enum flower_icmp_field field
)
251 if (eth_type
== htons(ETH_P_IP
) && ip_proto
== IPPROTO_ICMP
)
252 return field
== FLOWER_ICMP_FIELD_CODE
?
253 TCA_FLOWER_KEY_ICMPV4_CODE
:
254 TCA_FLOWER_KEY_ICMPV4_TYPE
;
255 else if (eth_type
== htons(ETH_P_IPV6
) && ip_proto
== IPPROTO_ICMPV6
)
256 return field
== FLOWER_ICMP_FIELD_CODE
?
257 TCA_FLOWER_KEY_ICMPV6_CODE
:
258 TCA_FLOWER_KEY_ICMPV6_TYPE
;
263 static int flower_parse_icmp(char *str
, __u16 eth_type
, __u8 ip_proto
,
264 enum flower_icmp_field field
, struct nlmsghdr
*n
)
270 type
= flower_icmp_attr_type(eth_type
, ip_proto
, field
);
274 ret
= get_u8(&value
, str
, 10);
278 addattr8(n
, MAX_MSG
, type
, value
);
283 static int flower_port_attr_type(__u8 ip_proto
, enum flower_endpoint endpoint
)
285 if (ip_proto
== IPPROTO_TCP
)
286 return endpoint
== FLOWER_ENDPOINT_SRC
?
287 TCA_FLOWER_KEY_TCP_SRC
:
288 TCA_FLOWER_KEY_TCP_DST
;
289 else if (ip_proto
== IPPROTO_UDP
)
290 return endpoint
== FLOWER_ENDPOINT_SRC
?
291 TCA_FLOWER_KEY_UDP_SRC
:
292 TCA_FLOWER_KEY_UDP_DST
;
293 else if (ip_proto
== IPPROTO_SCTP
)
294 return endpoint
== FLOWER_ENDPOINT_SRC
?
295 TCA_FLOWER_KEY_SCTP_SRC
:
296 TCA_FLOWER_KEY_SCTP_DST
;
301 static int flower_parse_port(char *str
, __u8 ip_proto
,
302 enum flower_endpoint endpoint
,
309 type
= flower_port_attr_type(ip_proto
, endpoint
);
313 ret
= get_be16(&port
, str
, 10);
317 addattr16(n
, MAX_MSG
, type
, port
);
322 static int flower_parse_key_id(const char *str
, int type
, struct nlmsghdr
*n
)
327 ret
= get_be32(&key_id
, str
, 10);
329 addattr32(n
, MAX_MSG
, type
, key_id
);
334 static int flower_parse_enc_port(char *str
, int type
, struct nlmsghdr
*n
)
339 ret
= get_be16(&port
, str
, 10);
343 addattr16(n
, MAX_MSG
, type
, port
);
348 static int flower_parse_opt(struct filter_util
*qu
, char *handle
,
349 int argc
, char **argv
, struct nlmsghdr
*n
)
352 struct tcmsg
*t
= NLMSG_DATA(n
);
354 __be16 eth_type
= TC_H_MIN(t
->tcm_info
);
355 __be16 vlan_ethtype
= 0;
356 __u8 ip_proto
= 0xff;
360 ret
= get_u32(&t
->tcm_handle
, handle
, 0);
362 fprintf(stderr
, "Illegal \"handle\"\n");
367 tail
= (struct rtattr
*) (((void *) n
) + NLMSG_ALIGN(n
->nlmsg_len
));
368 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
371 /*at minimal we will match all ethertype packets */
376 if (matches(*argv
, "classid") == 0 ||
377 matches(*argv
, "flowid") == 0) {
381 ret
= get_tc_classid(&handle
, *argv
);
383 fprintf(stderr
, "Illegal \"classid\"\n");
386 addattr_l(n
, MAX_MSG
, TCA_FLOWER_CLASSID
, &handle
, 4);
387 } else if (matches(*argv
, "matching_flags") == 0) {
389 ret
= flower_parse_matching_flags(*argv
,
390 TCA_FLOWER_KEY_FLAGS
,
391 TCA_FLOWER_KEY_FLAGS_MASK
,
394 fprintf(stderr
, "Illegal \"matching_flags\"\n");
397 } else if (matches(*argv
, "skip_hw") == 0) {
398 flags
|= TCA_CLS_FLAGS_SKIP_HW
;
399 } else if (matches(*argv
, "skip_sw") == 0) {
400 flags
|= TCA_CLS_FLAGS_SKIP_SW
;
401 } else if (matches(*argv
, "indev") == 0) {
402 char ifname
[IFNAMSIZ
] = {};
405 strncpy(ifname
, *argv
, sizeof(ifname
) - 1);
406 addattrstrz(n
, MAX_MSG
, TCA_FLOWER_INDEV
, ifname
);
407 } else if (matches(*argv
, "vlan_id") == 0) {
411 if (eth_type
!= htons(ETH_P_8021Q
)) {
413 "Can't set \"vlan_id\" if ethertype isn't 802.1Q\n");
416 ret
= get_u16(&vid
, *argv
, 10);
417 if (ret
< 0 || vid
& ~0xfff) {
418 fprintf(stderr
, "Illegal \"vlan_id\"\n");
421 addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_VLAN_ID
, vid
);
422 } else if (matches(*argv
, "vlan_prio") == 0) {
426 if (eth_type
!= htons(ETH_P_8021Q
)) {
428 "Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n");
431 ret
= get_u8(&vlan_prio
, *argv
, 10);
432 if (ret
< 0 || vlan_prio
& ~0x7) {
433 fprintf(stderr
, "Illegal \"vlan_prio\"\n");
437 TCA_FLOWER_KEY_VLAN_PRIO
, vlan_prio
);
438 } else if (matches(*argv
, "vlan_ethtype") == 0) {
440 ret
= flower_parse_vlan_eth_type(*argv
, eth_type
,
441 TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
445 } else if (matches(*argv
, "dst_mac") == 0) {
447 ret
= flower_parse_eth_addr(*argv
,
448 TCA_FLOWER_KEY_ETH_DST
,
449 TCA_FLOWER_KEY_ETH_DST_MASK
,
452 fprintf(stderr
, "Illegal \"dst_mac\"\n");
455 } else if (matches(*argv
, "src_mac") == 0) {
457 ret
= flower_parse_eth_addr(*argv
,
458 TCA_FLOWER_KEY_ETH_SRC
,
459 TCA_FLOWER_KEY_ETH_SRC_MASK
,
462 fprintf(stderr
, "Illegal \"src_mac\"\n");
465 } else if (matches(*argv
, "ip_proto") == 0) {
467 ret
= flower_parse_ip_proto(*argv
, vlan_ethtype
?
468 vlan_ethtype
: eth_type
,
469 TCA_FLOWER_KEY_IP_PROTO
,
472 fprintf(stderr
, "Illegal \"ip_proto\"\n");
475 } else if (matches(*argv
, "dst_ip") == 0) {
477 ret
= flower_parse_ip_addr(*argv
, vlan_ethtype
?
478 vlan_ethtype
: eth_type
,
479 TCA_FLOWER_KEY_IPV4_DST
,
480 TCA_FLOWER_KEY_IPV4_DST_MASK
,
481 TCA_FLOWER_KEY_IPV6_DST
,
482 TCA_FLOWER_KEY_IPV6_DST_MASK
,
485 fprintf(stderr
, "Illegal \"dst_ip\"\n");
488 } else if (matches(*argv
, "src_ip") == 0) {
490 ret
= flower_parse_ip_addr(*argv
, vlan_ethtype
?
491 vlan_ethtype
: eth_type
,
492 TCA_FLOWER_KEY_IPV4_SRC
,
493 TCA_FLOWER_KEY_IPV4_SRC_MASK
,
494 TCA_FLOWER_KEY_IPV6_SRC
,
495 TCA_FLOWER_KEY_IPV6_SRC_MASK
,
498 fprintf(stderr
, "Illegal \"src_ip\"\n");
501 } else if (matches(*argv
, "dst_port") == 0) {
503 ret
= flower_parse_port(*argv
, ip_proto
,
504 FLOWER_ENDPOINT_DST
, n
);
506 fprintf(stderr
, "Illegal \"dst_port\"\n");
509 } else if (matches(*argv
, "src_port") == 0) {
511 ret
= flower_parse_port(*argv
, ip_proto
,
512 FLOWER_ENDPOINT_SRC
, n
);
514 fprintf(stderr
, "Illegal \"src_port\"\n");
517 } else if (matches(*argv
, "type") == 0) {
519 ret
= flower_parse_icmp(*argv
, eth_type
, ip_proto
,
520 FLOWER_ICMP_FIELD_TYPE
, n
);
522 fprintf(stderr
, "Illegal \"icmp type\"\n");
525 } else if (matches(*argv
, "code") == 0) {
527 ret
= flower_parse_icmp(*argv
, eth_type
, ip_proto
,
528 FLOWER_ICMP_FIELD_CODE
, n
);
530 fprintf(stderr
, "Illegal \"icmp code\"\n");
533 } else if (matches(*argv
, "enc_dst_ip") == 0) {
535 ret
= flower_parse_ip_addr(*argv
, 0,
536 TCA_FLOWER_KEY_ENC_IPV4_DST
,
537 TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
,
538 TCA_FLOWER_KEY_ENC_IPV6_DST
,
539 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
,
542 fprintf(stderr
, "Illegal \"enc_dst_ip\"\n");
545 } else if (matches(*argv
, "enc_src_ip") == 0) {
547 ret
= flower_parse_ip_addr(*argv
, 0,
548 TCA_FLOWER_KEY_ENC_IPV4_SRC
,
549 TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
,
550 TCA_FLOWER_KEY_ENC_IPV6_SRC
,
551 TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
,
554 fprintf(stderr
, "Illegal \"enc_src_ip\"\n");
557 } else if (matches(*argv
, "enc_key_id") == 0) {
559 ret
= flower_parse_key_id(*argv
,
560 TCA_FLOWER_KEY_ENC_KEY_ID
, n
);
562 fprintf(stderr
, "Illegal \"enc_key_id\"\n");
565 } else if (matches(*argv
, "enc_dst_port") == 0) {
567 ret
= flower_parse_enc_port(*argv
,
568 TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, n
);
570 fprintf(stderr
, "Illegal \"enc_dst_port\"\n");
573 } else if (matches(*argv
, "action") == 0) {
575 ret
= parse_action(&argc
, &argv
, TCA_FLOWER_ACT
, n
);
577 fprintf(stderr
, "Illegal \"action\"\n");
581 } else if (strcmp(*argv
, "help") == 0) {
585 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
593 addattr32(n
, MAX_MSG
, TCA_FLOWER_FLAGS
, flags
);
595 ret
= addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_ETH_TYPE
, eth_type
);
597 fprintf(stderr
, "Illegal \"eth_type\"(0x%x)\n",
602 tail
->rta_len
= (((void *)n
)+n
->nlmsg_len
) - (void *)tail
;
607 static int __mask_bits(char *addr
, size_t len
)
614 for (i
= 0; i
< len
; i
++, addr
++) {
615 for (j
= 7; j
>= 0; j
--) {
616 if (((*addr
) >> j
) & 0x1) {
630 static void flower_print_eth_addr(FILE *f
, char *name
,
631 struct rtattr
*addr_attr
,
632 struct rtattr
*mask_attr
)
637 if (!addr_attr
|| RTA_PAYLOAD(addr_attr
) != ETH_ALEN
)
639 fprintf(f
, "\n %s %s", name
, ll_addr_n2a(RTA_DATA(addr_attr
), ETH_ALEN
,
641 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != ETH_ALEN
)
643 bits
= __mask_bits(RTA_DATA(mask_attr
), ETH_ALEN
);
645 fprintf(f
, "/%s", ll_addr_n2a(RTA_DATA(mask_attr
), ETH_ALEN
,
647 else if (bits
< ETH_ALEN
* 8)
648 fprintf(f
, "/%d", bits
);
651 static void flower_print_eth_type(FILE *f
, __be16
*p_eth_type
,
652 struct rtattr
*eth_type_attr
)
659 eth_type
= rta_getattr_u16(eth_type_attr
);
660 fprintf(f
, "\n eth_type ");
661 if (eth_type
== htons(ETH_P_IP
))
663 else if (eth_type
== htons(ETH_P_IPV6
))
666 fprintf(f
, "%04x", ntohs(eth_type
));
667 *p_eth_type
= eth_type
;
670 static void flower_print_ip_proto(FILE *f
, __u8
*p_ip_proto
,
671 struct rtattr
*ip_proto_attr
)
678 ip_proto
= rta_getattr_u8(ip_proto_attr
);
679 fprintf(f
, "\n ip_proto ");
680 if (ip_proto
== IPPROTO_TCP
)
682 else if (ip_proto
== IPPROTO_UDP
)
684 else if (ip_proto
== IPPROTO_SCTP
)
686 else if (ip_proto
== IPPROTO_ICMP
)
688 else if (ip_proto
== IPPROTO_ICMPV6
)
689 fprintf(f
, "icmpv6");
691 fprintf(f
, "%02x", ip_proto
);
692 *p_ip_proto
= ip_proto
;
695 static void flower_print_matching_flags(FILE *f
, char *name
,
697 struct rtattr
*mask_attr
)
699 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != 4)
702 fprintf(f
, "\n %s 0x%08x/0x%08x", name
, ntohl(rta_getattr_u32(attr
)),
703 mask_attr
? ntohl(rta_getattr_u32(mask_attr
)) : 0xffffffff);
706 static void flower_print_ip_addr(FILE *f
, char *name
, __be16 eth_type
,
707 struct rtattr
*addr4_attr
,
708 struct rtattr
*mask4_attr
,
709 struct rtattr
*addr6_attr
,
710 struct rtattr
*mask6_attr
)
712 struct rtattr
*addr_attr
;
713 struct rtattr
*mask_attr
;
718 if (eth_type
== htons(ETH_P_IP
)) {
720 addr_attr
= addr4_attr
;
721 mask_attr
= mask4_attr
;
723 } else if (eth_type
== htons(ETH_P_IPV6
)) {
725 addr_attr
= addr6_attr
;
726 mask_attr
= mask6_attr
;
731 if (!addr_attr
|| RTA_PAYLOAD(addr_attr
) != len
)
733 fprintf(f
, "\n %s %s", name
, rt_addr_n2a_rta(family
, addr_attr
));
734 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != len
)
736 bits
= __mask_bits(RTA_DATA(mask_attr
), len
);
738 fprintf(f
, "/%s", rt_addr_n2a_rta(family
, mask_attr
));
739 else if (bits
< len
* 8)
740 fprintf(f
, "/%d", bits
);
743 static void flower_print_port(FILE *f
, char *name
, struct rtattr
*attr
)
746 fprintf(f
, "\n %s %d", name
, rta_getattr_be16(attr
));
749 static void flower_print_key_id(FILE *f
, const char *name
,
753 fprintf(f
, "\n %s %d", name
, rta_getattr_be32(attr
));
756 static void flower_print_icmp(FILE *f
, char *name
, struct rtattr
*attr
)
759 fprintf(f
, "\n %s %d", name
, rta_getattr_u8(attr
));
762 static int flower_print_opt(struct filter_util
*qu
, FILE *f
,
763 struct rtattr
*opt
, __u32 handle
)
765 struct rtattr
*tb
[TCA_FLOWER_MAX
+ 1];
767 __u8 ip_proto
= 0xff;
773 parse_rtattr_nested(tb
, TCA_FLOWER_MAX
, opt
);
776 fprintf(f
, "handle 0x%x ", handle
);
778 if (tb
[TCA_FLOWER_CLASSID
]) {
780 fprintf(f
, "classid %s ",
781 sprint_tc_classid(rta_getattr_u32(tb
[TCA_FLOWER_CLASSID
]),
785 if (tb
[TCA_FLOWER_INDEV
]) {
786 struct rtattr
*attr
= tb
[TCA_FLOWER_INDEV
];
788 fprintf(f
, "\n indev %s", rta_getattr_str(attr
));
791 if (tb
[TCA_FLOWER_KEY_VLAN_ID
]) {
792 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_VLAN_ID
];
794 fprintf(f
, "\n vlan_id %d", rta_getattr_u16(attr
));
797 if (tb
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
798 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_VLAN_PRIO
];
800 fprintf(f
, "\n vlan_prio %d", rta_getattr_u8(attr
));
803 flower_print_eth_addr(f
, "dst_mac", tb
[TCA_FLOWER_KEY_ETH_DST
],
804 tb
[TCA_FLOWER_KEY_ETH_DST_MASK
]);
805 flower_print_eth_addr(f
, "src_mac", tb
[TCA_FLOWER_KEY_ETH_SRC
],
806 tb
[TCA_FLOWER_KEY_ETH_SRC_MASK
]);
808 flower_print_eth_type(f
, ð_type
, tb
[TCA_FLOWER_KEY_ETH_TYPE
]);
809 flower_print_ip_proto(f
, &ip_proto
, tb
[TCA_FLOWER_KEY_IP_PROTO
]);
811 flower_print_ip_addr(f
, "dst_ip", eth_type
,
812 tb
[TCA_FLOWER_KEY_IPV4_DST
],
813 tb
[TCA_FLOWER_KEY_IPV4_DST_MASK
],
814 tb
[TCA_FLOWER_KEY_IPV6_DST
],
815 tb
[TCA_FLOWER_KEY_IPV6_DST_MASK
]);
817 flower_print_ip_addr(f
, "src_ip", eth_type
,
818 tb
[TCA_FLOWER_KEY_IPV4_SRC
],
819 tb
[TCA_FLOWER_KEY_IPV4_SRC_MASK
],
820 tb
[TCA_FLOWER_KEY_IPV6_SRC
],
821 tb
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]);
823 nl_type
= flower_port_attr_type(ip_proto
, false);
825 flower_print_port(f
, "dst_port", tb
[nl_type
]);
826 nl_type
= flower_port_attr_type(ip_proto
, true);
828 flower_print_port(f
, "src_port", tb
[nl_type
]);
830 nl_type
= flower_icmp_attr_type(eth_type
, ip_proto
, false);
832 flower_print_icmp(f
, "icmp_type", tb
[nl_type
]);
833 nl_type
= flower_icmp_attr_type(eth_type
, ip_proto
, true);
835 flower_print_icmp(f
, "icmp_code", tb
[nl_type
]);
837 flower_print_ip_addr(f
, "enc_dst_ip",
838 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
] ?
839 htons(ETH_P_IP
) : htons(ETH_P_IPV6
),
840 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST
],
841 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
],
842 tb
[TCA_FLOWER_KEY_ENC_IPV6_DST
],
843 tb
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]);
845 flower_print_ip_addr(f
, "enc_src_ip",
846 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
] ?
847 htons(ETH_P_IP
) : htons(ETH_P_IPV6
),
848 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC
],
849 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
],
850 tb
[TCA_FLOWER_KEY_ENC_IPV6_SRC
],
851 tb
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]);
853 flower_print_key_id(f
, "enc_key_id",
854 tb
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
856 flower_print_port(f
, "enc_dst_port",
857 tb
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
859 flower_print_matching_flags(f
, "matching_flags",
860 tb
[TCA_FLOWER_KEY_FLAGS
],
861 tb
[TCA_FLOWER_KEY_FLAGS_MASK
]);
863 if (tb
[TCA_FLOWER_FLAGS
]) {
864 __u32 flags
= rta_getattr_u32(tb
[TCA_FLOWER_FLAGS
]);
866 if (flags
& TCA_CLS_FLAGS_SKIP_HW
)
867 fprintf(f
, "\n skip_hw");
868 if (flags
& TCA_CLS_FLAGS_SKIP_SW
)
869 fprintf(f
, "\n skip_sw");
872 if (tb
[TCA_FLOWER_ACT
])
873 tc_print_action(f
, tb
[TCA_FLOWER_ACT
]);
878 struct filter_util flower_filter_util
= {
880 .parse_fopt
= flower_parse_opt
,
881 .print_fopt
= flower_print_opt
,