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 MAC-ADDR |\n"
49 " src_mac MAC-ADDR |\n"
50 " ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
51 " dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
52 " src_ip [ IPV4-ADDR | IPV6-ADDR ] |\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 " enc_dst_port [ UDP-PORT ] }\n"
61 " FILTERID := X:Y:Z\n"
62 " ACTION-SPEC := ... look at individual actions\n"
64 "NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n"
65 "NOTE: There can be only used one mask per one prio. If user needs\n"
66 " to specify different mask, he has to use different prio.\n");
69 static int flower_parse_eth_addr(char *str
, int addr_type
, int mask_type
,
75 ret
= ll_addr_a2n(addr
, sizeof(addr
), str
);
78 addattr_l(n
, MAX_MSG
, addr_type
, addr
, sizeof(addr
));
79 memset(addr
, 0xff, ETH_ALEN
);
80 addattr_l(n
, MAX_MSG
, mask_type
, addr
, sizeof(addr
));
84 static int flower_parse_vlan_eth_type(char *str
, __be16 eth_type
, int type
,
85 __be16
*p_vlan_eth_type
,
90 if (eth_type
!= htons(ETH_P_8021Q
)) {
92 "Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n");
96 if (ll_proto_a2n(&vlan_eth_type
, str
))
97 invarg("invalid vlan_ethtype", str
);
98 addattr16(n
, MAX_MSG
, type
, vlan_eth_type
);
99 *p_vlan_eth_type
= vlan_eth_type
;
103 static int flower_parse_ip_proto(char *str
, __be16 eth_type
, int type
,
104 __u8
*p_ip_proto
, struct nlmsghdr
*n
)
109 if (eth_type
!= htons(ETH_P_IP
) && eth_type
!= htons(ETH_P_IPV6
))
112 if (matches(str
, "tcp") == 0) {
113 ip_proto
= IPPROTO_TCP
;
114 } else if (matches(str
, "udp") == 0) {
115 ip_proto
= IPPROTO_UDP
;
116 } else if (matches(str
, "sctp") == 0) {
117 ip_proto
= IPPROTO_SCTP
;
118 } else if (matches(str
, "icmp") == 0) {
119 if (eth_type
!= htons(ETH_P_IP
))
121 ip_proto
= IPPROTO_ICMP
;
122 } else if (matches(str
, "icmpv6") == 0) {
123 if (eth_type
!= htons(ETH_P_IPV6
))
125 ip_proto
= IPPROTO_ICMPV6
;
127 ret
= get_u8(&ip_proto
, str
, 16);
131 addattr8(n
, MAX_MSG
, type
, ip_proto
);
132 *p_ip_proto
= ip_proto
;
136 fprintf(stderr
, "Illegal \"eth_type\" for ip proto\n");
140 static int flower_parse_ip_addr(char *str
, __be16 eth_type
,
141 int addr4_type
, int mask4_type
,
142 int addr6_type
, int mask6_type
,
151 if (eth_type
== htons(ETH_P_IP
)) {
153 } else if (eth_type
== htons(ETH_P_IPV6
)) {
155 } else if (!eth_type
) {
161 ret
= get_prefix(&addr
, str
, family
);
165 if (family
&& (addr
.family
!= family
)) {
166 fprintf(stderr
, "Illegal \"eth_type\" for ip address\n");
170 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? addr4_type
: addr6_type
,
171 addr
.data
, addr
.bytelen
);
173 memset(addr
.data
, 0xff, addr
.bytelen
);
175 for (i
= 0; i
< addr
.bytelen
/ 4; i
++) {
178 } else if (bits
/ 32 >= 1) {
181 addr
.data
[i
] <<= 32 - bits
;
182 addr
.data
[i
] = htonl(addr
.data
[i
]);
187 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? mask4_type
: mask6_type
,
188 addr
.data
, addr
.bytelen
);
193 static int flower_icmp_attr_type(__be16 eth_type
, __u8 ip_proto
,
194 enum flower_icmp_field field
)
196 if (eth_type
== htons(ETH_P_IP
) && ip_proto
== IPPROTO_ICMP
)
197 return field
== FLOWER_ICMP_FIELD_CODE
?
198 TCA_FLOWER_KEY_ICMPV4_CODE
:
199 TCA_FLOWER_KEY_ICMPV4_TYPE
;
200 else if (eth_type
== htons(ETH_P_IPV6
) && ip_proto
== IPPROTO_ICMPV6
)
201 return field
== FLOWER_ICMP_FIELD_CODE
?
202 TCA_FLOWER_KEY_ICMPV6_CODE
:
203 TCA_FLOWER_KEY_ICMPV6_TYPE
;
208 static int flower_parse_icmp(char *str
, __u16 eth_type
, __u8 ip_proto
,
209 enum flower_icmp_field field
, struct nlmsghdr
*n
)
215 type
= flower_icmp_attr_type(eth_type
, ip_proto
, field
);
219 ret
= get_u8(&value
, str
, 10);
223 addattr8(n
, MAX_MSG
, type
, value
);
228 static int flower_port_attr_type(__u8 ip_proto
, enum flower_endpoint endpoint
)
230 if (ip_proto
== IPPROTO_TCP
)
231 return endpoint
== FLOWER_ENDPOINT_SRC
?
232 TCA_FLOWER_KEY_TCP_SRC
:
233 TCA_FLOWER_KEY_TCP_DST
;
234 else if (ip_proto
== IPPROTO_UDP
)
235 return endpoint
== FLOWER_ENDPOINT_SRC
?
236 TCA_FLOWER_KEY_UDP_SRC
:
237 TCA_FLOWER_KEY_UDP_DST
;
238 else if (ip_proto
== IPPROTO_SCTP
)
239 return endpoint
== FLOWER_ENDPOINT_SRC
?
240 TCA_FLOWER_KEY_SCTP_SRC
:
241 TCA_FLOWER_KEY_SCTP_DST
;
246 static int flower_parse_port(char *str
, __u8 ip_proto
,
247 enum flower_endpoint endpoint
,
254 type
= flower_port_attr_type(ip_proto
, endpoint
);
258 ret
= get_be16(&port
, str
, 10);
262 addattr16(n
, MAX_MSG
, type
, port
);
267 static int flower_parse_key_id(const char *str
, int type
, struct nlmsghdr
*n
)
272 ret
= get_be32(&key_id
, str
, 10);
274 addattr32(n
, MAX_MSG
, type
, key_id
);
279 static int flower_parse_enc_port(char *str
, int type
, struct nlmsghdr
*n
)
284 ret
= get_be16(&port
, str
, 10);
288 addattr16(n
, MAX_MSG
, type
, port
);
293 static int flower_parse_opt(struct filter_util
*qu
, char *handle
,
294 int argc
, char **argv
, struct nlmsghdr
*n
)
297 struct tcmsg
*t
= NLMSG_DATA(n
);
299 __be16 eth_type
= TC_H_MIN(t
->tcm_info
);
300 __be16 vlan_ethtype
= 0;
301 __u8 ip_proto
= 0xff;
305 ret
= get_u32(&t
->tcm_handle
, handle
, 0);
307 fprintf(stderr
, "Illegal \"handle\"\n");
312 tail
= (struct rtattr
*) (((void *) n
) + NLMSG_ALIGN(n
->nlmsg_len
));
313 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
316 /*at minimal we will match all ethertype packets */
321 if (matches(*argv
, "classid") == 0 ||
322 matches(*argv
, "flowid") == 0) {
326 ret
= get_tc_classid(&handle
, *argv
);
328 fprintf(stderr
, "Illegal \"classid\"\n");
331 addattr_l(n
, MAX_MSG
, TCA_FLOWER_CLASSID
, &handle
, 4);
332 } else if (matches(*argv
, "skip_hw") == 0) {
333 flags
|= TCA_CLS_FLAGS_SKIP_HW
;
334 } else if (matches(*argv
, "skip_sw") == 0) {
335 flags
|= TCA_CLS_FLAGS_SKIP_SW
;
336 } else if (matches(*argv
, "indev") == 0) {
337 char ifname
[IFNAMSIZ
] = {};
340 strncpy(ifname
, *argv
, sizeof(ifname
) - 1);
341 addattrstrz(n
, MAX_MSG
, TCA_FLOWER_INDEV
, ifname
);
342 } else if (matches(*argv
, "vlan_id") == 0) {
346 if (eth_type
!= htons(ETH_P_8021Q
)) {
348 "Can't set \"vlan_id\" if ethertype isn't 802.1Q\n");
351 ret
= get_u16(&vid
, *argv
, 10);
352 if (ret
< 0 || vid
& ~0xfff) {
353 fprintf(stderr
, "Illegal \"vlan_id\"\n");
356 addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_VLAN_ID
, vid
);
357 } else if (matches(*argv
, "vlan_prio") == 0) {
361 if (eth_type
!= htons(ETH_P_8021Q
)) {
363 "Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n");
366 ret
= get_u8(&vlan_prio
, *argv
, 10);
367 if (ret
< 0 || vlan_prio
& ~0x7) {
368 fprintf(stderr
, "Illegal \"vlan_prio\"\n");
372 TCA_FLOWER_KEY_VLAN_PRIO
, vlan_prio
);
373 } else if (matches(*argv
, "vlan_ethtype") == 0) {
375 ret
= flower_parse_vlan_eth_type(*argv
, eth_type
,
376 TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
380 } else if (matches(*argv
, "dst_mac") == 0) {
382 ret
= flower_parse_eth_addr(*argv
,
383 TCA_FLOWER_KEY_ETH_DST
,
384 TCA_FLOWER_KEY_ETH_DST_MASK
,
387 fprintf(stderr
, "Illegal \"dst_mac\"\n");
390 } else if (matches(*argv
, "src_mac") == 0) {
392 ret
= flower_parse_eth_addr(*argv
,
393 TCA_FLOWER_KEY_ETH_SRC
,
394 TCA_FLOWER_KEY_ETH_SRC_MASK
,
397 fprintf(stderr
, "Illegal \"src_mac\"\n");
400 } else if (matches(*argv
, "ip_proto") == 0) {
402 ret
= flower_parse_ip_proto(*argv
, vlan_ethtype
?
403 vlan_ethtype
: eth_type
,
404 TCA_FLOWER_KEY_IP_PROTO
,
407 fprintf(stderr
, "Illegal \"ip_proto\"\n");
410 } else if (matches(*argv
, "dst_ip") == 0) {
412 ret
= flower_parse_ip_addr(*argv
, vlan_ethtype
?
413 vlan_ethtype
: eth_type
,
414 TCA_FLOWER_KEY_IPV4_DST
,
415 TCA_FLOWER_KEY_IPV4_DST_MASK
,
416 TCA_FLOWER_KEY_IPV6_DST
,
417 TCA_FLOWER_KEY_IPV6_DST_MASK
,
420 fprintf(stderr
, "Illegal \"dst_ip\"\n");
423 } else if (matches(*argv
, "src_ip") == 0) {
425 ret
= flower_parse_ip_addr(*argv
, vlan_ethtype
?
426 vlan_ethtype
: eth_type
,
427 TCA_FLOWER_KEY_IPV4_SRC
,
428 TCA_FLOWER_KEY_IPV4_SRC_MASK
,
429 TCA_FLOWER_KEY_IPV6_SRC
,
430 TCA_FLOWER_KEY_IPV6_SRC_MASK
,
433 fprintf(stderr
, "Illegal \"src_ip\"\n");
436 } else if (matches(*argv
, "dst_port") == 0) {
438 ret
= flower_parse_port(*argv
, ip_proto
,
439 FLOWER_ENDPOINT_DST
, n
);
441 fprintf(stderr
, "Illegal \"dst_port\"\n");
444 } else if (matches(*argv
, "src_port") == 0) {
446 ret
= flower_parse_port(*argv
, ip_proto
,
447 FLOWER_ENDPOINT_SRC
, n
);
449 fprintf(stderr
, "Illegal \"src_port\"\n");
452 } else if (matches(*argv
, "type") == 0) {
454 ret
= flower_parse_icmp(*argv
, eth_type
, ip_proto
,
455 FLOWER_ICMP_FIELD_TYPE
, n
);
457 fprintf(stderr
, "Illegal \"icmp type\"\n");
460 } else if (matches(*argv
, "code") == 0) {
462 ret
= flower_parse_icmp(*argv
, eth_type
, ip_proto
,
463 FLOWER_ICMP_FIELD_CODE
, n
);
465 fprintf(stderr
, "Illegal \"icmp code\"\n");
468 } else if (matches(*argv
, "enc_dst_ip") == 0) {
470 ret
= flower_parse_ip_addr(*argv
, 0,
471 TCA_FLOWER_KEY_ENC_IPV4_DST
,
472 TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
,
473 TCA_FLOWER_KEY_ENC_IPV6_DST
,
474 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
,
477 fprintf(stderr
, "Illegal \"enc_dst_ip\"\n");
480 } else if (matches(*argv
, "enc_src_ip") == 0) {
482 ret
= flower_parse_ip_addr(*argv
, 0,
483 TCA_FLOWER_KEY_ENC_IPV4_SRC
,
484 TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
,
485 TCA_FLOWER_KEY_ENC_IPV6_SRC
,
486 TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
,
489 fprintf(stderr
, "Illegal \"enc_src_ip\"\n");
492 } else if (matches(*argv
, "enc_key_id") == 0) {
494 ret
= flower_parse_key_id(*argv
,
495 TCA_FLOWER_KEY_ENC_KEY_ID
, n
);
497 fprintf(stderr
, "Illegal \"enc_key_id\"\n");
500 } else if (matches(*argv
, "enc_dst_port") == 0) {
502 ret
= flower_parse_enc_port(*argv
,
503 TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, n
);
505 fprintf(stderr
, "Illegal \"enc_dst_port\"\n");
508 } else if (matches(*argv
, "action") == 0) {
510 ret
= parse_action(&argc
, &argv
, TCA_FLOWER_ACT
, n
);
512 fprintf(stderr
, "Illegal \"action\"\n");
516 } else if (strcmp(*argv
, "help") == 0) {
520 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
528 addattr32(n
, MAX_MSG
, TCA_FLOWER_FLAGS
, flags
);
530 ret
= addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_ETH_TYPE
, eth_type
);
532 fprintf(stderr
, "Illegal \"eth_type\"(0x%x)\n",
537 tail
->rta_len
= (((void *)n
)+n
->nlmsg_len
) - (void *)tail
;
542 static int __mask_bits(char *addr
, size_t len
)
549 for (i
= 0; i
< len
; i
++, addr
++) {
550 for (j
= 7; j
>= 0; j
--) {
551 if (((*addr
) >> j
) & 0x1) {
565 static void flower_print_eth_addr(FILE *f
, char *name
,
566 struct rtattr
*addr_attr
,
567 struct rtattr
*mask_attr
)
572 if (!addr_attr
|| RTA_PAYLOAD(addr_attr
) != ETH_ALEN
)
574 fprintf(f
, "\n %s %s", name
, ll_addr_n2a(RTA_DATA(addr_attr
), ETH_ALEN
,
576 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != ETH_ALEN
)
578 bits
= __mask_bits(RTA_DATA(mask_attr
), ETH_ALEN
);
580 fprintf(f
, "/%s", ll_addr_n2a(RTA_DATA(mask_attr
), ETH_ALEN
,
582 else if (bits
< ETH_ALEN
* 8)
583 fprintf(f
, "/%d", bits
);
586 static void flower_print_eth_type(FILE *f
, __be16
*p_eth_type
,
587 struct rtattr
*eth_type_attr
)
594 eth_type
= rta_getattr_u16(eth_type_attr
);
595 fprintf(f
, "\n eth_type ");
596 if (eth_type
== htons(ETH_P_IP
))
598 else if (eth_type
== htons(ETH_P_IPV6
))
601 fprintf(f
, "%04x", ntohs(eth_type
));
602 *p_eth_type
= eth_type
;
605 static void flower_print_ip_proto(FILE *f
, __u8
*p_ip_proto
,
606 struct rtattr
*ip_proto_attr
)
613 ip_proto
= rta_getattr_u8(ip_proto_attr
);
614 fprintf(f
, "\n ip_proto ");
615 if (ip_proto
== IPPROTO_TCP
)
617 else if (ip_proto
== IPPROTO_UDP
)
619 else if (ip_proto
== IPPROTO_SCTP
)
621 else if (ip_proto
== IPPROTO_ICMP
)
623 else if (ip_proto
== IPPROTO_ICMPV6
)
624 fprintf(f
, "icmpv6");
626 fprintf(f
, "%02x", ip_proto
);
627 *p_ip_proto
= ip_proto
;
630 static void flower_print_ip_addr(FILE *f
, char *name
, __be16 eth_type
,
631 struct rtattr
*addr4_attr
,
632 struct rtattr
*mask4_attr
,
633 struct rtattr
*addr6_attr
,
634 struct rtattr
*mask6_attr
)
636 struct rtattr
*addr_attr
;
637 struct rtattr
*mask_attr
;
642 if (eth_type
== htons(ETH_P_IP
)) {
644 addr_attr
= addr4_attr
;
645 mask_attr
= mask4_attr
;
647 } else if (eth_type
== htons(ETH_P_IPV6
)) {
649 addr_attr
= addr6_attr
;
650 mask_attr
= mask6_attr
;
655 if (!addr_attr
|| RTA_PAYLOAD(addr_attr
) != len
)
657 fprintf(f
, "\n %s %s", name
, rt_addr_n2a_rta(family
, addr_attr
));
658 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != len
)
660 bits
= __mask_bits(RTA_DATA(mask_attr
), len
);
662 fprintf(f
, "/%s", rt_addr_n2a_rta(family
, mask_attr
));
663 else if (bits
< len
* 8)
664 fprintf(f
, "/%d", bits
);
667 static void flower_print_port(FILE *f
, char *name
, struct rtattr
*attr
)
670 fprintf(f
, "\n %s %d", name
, rta_getattr_be16(attr
));
673 static void flower_print_key_id(FILE *f
, const char *name
,
677 fprintf(f
, "\n %s %d", name
, rta_getattr_be32(attr
));
680 static void flower_print_icmp(FILE *f
, char *name
, struct rtattr
*attr
)
683 fprintf(f
, "\n %s %d", name
, rta_getattr_u8(attr
));
686 static int flower_print_opt(struct filter_util
*qu
, FILE *f
,
687 struct rtattr
*opt
, __u32 handle
)
689 struct rtattr
*tb
[TCA_FLOWER_MAX
+ 1];
691 __u8 ip_proto
= 0xff;
697 parse_rtattr_nested(tb
, TCA_FLOWER_MAX
, opt
);
700 fprintf(f
, "handle 0x%x ", handle
);
702 if (tb
[TCA_FLOWER_CLASSID
]) {
704 fprintf(f
, "classid %s ",
705 sprint_tc_classid(rta_getattr_u32(tb
[TCA_FLOWER_CLASSID
]),
709 if (tb
[TCA_FLOWER_INDEV
]) {
710 struct rtattr
*attr
= tb
[TCA_FLOWER_INDEV
];
712 fprintf(f
, "\n indev %s", rta_getattr_str(attr
));
715 if (tb
[TCA_FLOWER_KEY_VLAN_ID
]) {
716 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_VLAN_ID
];
718 fprintf(f
, "\n vlan_id %d", rta_getattr_u16(attr
));
721 if (tb
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
722 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_VLAN_PRIO
];
724 fprintf(f
, "\n vlan_prio %d", rta_getattr_u8(attr
));
727 flower_print_eth_addr(f
, "dst_mac", tb
[TCA_FLOWER_KEY_ETH_DST
],
728 tb
[TCA_FLOWER_KEY_ETH_DST_MASK
]);
729 flower_print_eth_addr(f
, "src_mac", tb
[TCA_FLOWER_KEY_ETH_SRC
],
730 tb
[TCA_FLOWER_KEY_ETH_SRC_MASK
]);
732 flower_print_eth_type(f
, ð_type
, tb
[TCA_FLOWER_KEY_ETH_TYPE
]);
733 flower_print_ip_proto(f
, &ip_proto
, tb
[TCA_FLOWER_KEY_IP_PROTO
]);
735 flower_print_ip_addr(f
, "dst_ip", eth_type
,
736 tb
[TCA_FLOWER_KEY_IPV4_DST
],
737 tb
[TCA_FLOWER_KEY_IPV4_DST_MASK
],
738 tb
[TCA_FLOWER_KEY_IPV6_DST
],
739 tb
[TCA_FLOWER_KEY_IPV6_DST_MASK
]);
741 flower_print_ip_addr(f
, "src_ip", eth_type
,
742 tb
[TCA_FLOWER_KEY_IPV4_SRC
],
743 tb
[TCA_FLOWER_KEY_IPV4_SRC_MASK
],
744 tb
[TCA_FLOWER_KEY_IPV6_SRC
],
745 tb
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]);
747 nl_type
= flower_port_attr_type(ip_proto
, FLOWER_ENDPOINT_DST
);
749 flower_print_port(f
, "dst_port", tb
[nl_type
]);
750 nl_type
= flower_port_attr_type(ip_proto
, FLOWER_ENDPOINT_SRC
);
752 flower_print_port(f
, "src_port", tb
[nl_type
]);
754 nl_type
= flower_icmp_attr_type(eth_type
, ip_proto
, false);
756 flower_print_icmp(f
, "icmp_type", tb
[nl_type
]);
757 nl_type
= flower_icmp_attr_type(eth_type
, ip_proto
, true);
759 flower_print_icmp(f
, "icmp_code", tb
[nl_type
]);
761 flower_print_ip_addr(f
, "enc_dst_ip",
762 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
] ?
763 htons(ETH_P_IP
) : htons(ETH_P_IPV6
),
764 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST
],
765 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
],
766 tb
[TCA_FLOWER_KEY_ENC_IPV6_DST
],
767 tb
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]);
769 flower_print_ip_addr(f
, "enc_src_ip",
770 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
] ?
771 htons(ETH_P_IP
) : htons(ETH_P_IPV6
),
772 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC
],
773 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
],
774 tb
[TCA_FLOWER_KEY_ENC_IPV6_SRC
],
775 tb
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]);
777 flower_print_key_id(f
, "enc_key_id",
778 tb
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
780 flower_print_port(f
, "enc_dst_port",
781 tb
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
783 if (tb
[TCA_FLOWER_FLAGS
]) {
784 __u32 flags
= rta_getattr_u32(tb
[TCA_FLOWER_FLAGS
]);
786 if (flags
& TCA_CLS_FLAGS_SKIP_HW
)
787 fprintf(f
, "\n skip_hw");
788 if (flags
& TCA_CLS_FLAGS_SKIP_SW
)
789 fprintf(f
, "\n skip_sw");
792 if (tb
[TCA_FLOWER_ACT
])
793 tc_print_action(f
, tb
[TCA_FLOWER_ACT
]);
798 struct filter_util flower_filter_util
= {
800 .parse_fopt
= flower_parse_opt
,
801 .print_fopt
= flower_print_opt
,