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>
17 #include <linux/limits.h>
18 #include <linux/if_arp.h>
19 #include <linux/if_ether.h>
21 #include <linux/tc_act/tc_vlan.h>
22 #include <linux/mpls.h>
28 enum flower_matching_flags
{
32 enum flower_endpoint
{
37 enum flower_icmp_field
{
38 FLOWER_ICMP_FIELD_TYPE
,
39 FLOWER_ICMP_FIELD_CODE
42 static void explain(void)
45 "Usage: ... flower [ MATCH-LIST ] [ verbose ]\n"
46 " [ skip_sw | skip_hw ]\n"
47 " [ action ACTION-SPEC ] [ classid CLASSID ]\n"
49 "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"
50 " MATCH := { indev DEV-NAME |\n"
52 " vlan_prio PRIORITY |\n"
53 " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
55 " cvlan_prio PRIORITY |\n"
56 " cvlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
57 " dst_mac MASKED-LLADDR |\n"
58 " src_mac MASKED-LLADDR |\n"
59 " ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
60 " ip_tos MASKED-IP_TOS |\n"
61 " ip_ttl MASKED-IP_TTL |\n"
62 " mpls_label LABEL |\n"
68 " dst_port PORT-NUMBER |\n"
69 " src_port PORT-NUMBER |\n"
70 " tcp_flags MASKED-TCP_FLAGS |\n"
71 " type MASKED-ICMP-TYPE |\n"
72 " code MASKED-ICMP-CODE |\n"
73 " arp_tip IPV4-PREFIX |\n"
74 " arp_sip IPV4-PREFIX |\n"
75 " arp_op [ request | reply | OP ] |\n"
76 " arp_tha MASKED-LLADDR |\n"
77 " arp_sha MASKED-LLADDR |\n"
78 " enc_dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
79 " enc_src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
80 " enc_key_id [ KEY-ID ] |\n"
81 " enc_tos MASKED-IP_TOS |\n"
82 " enc_ttl MASKED-IP_TTL |\n"
83 " geneve_opts MASKED-OPTIONS |\n"
84 " ip_flags IP-FLAGS | \n"
85 " enc_dst_port [ port_number ] |\n"
86 " ct_state MASKED_CT_STATE |\n"
87 " ct_label MASKED_CT_LABEL |\n"
88 " ct_mark MASKED_CT_MARK |\n"
89 " ct_zone MASKED_CT_ZONE }\n"
90 " FILTERID := X:Y:Z\n"
91 " MASKED_LLADDR := { LLADDR | LLADDR/MASK | LLADDR/BITS }\n"
92 " MASKED_CT_STATE := combination of {+|-} and flags trk,est,new\n"
93 " ACTION-SPEC := ... look at individual actions\n"
95 "NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n"
96 "NOTE: There can be only used one mask per one prio. If user needs\n"
97 " to specify different mask, he has to use different prio.\n");
100 static int flower_parse_eth_addr(char *str
, int addr_type
, int mask_type
,
104 char addr
[ETH_ALEN
], *slash
;
106 slash
= strchr(str
, '/');
110 ret
= ll_addr_a2n(addr
, sizeof(addr
), str
);
113 addattr_l(n
, MAX_MSG
, addr_type
, addr
, sizeof(addr
));
118 if (!get_unsigned(&bits
, slash
+ 1, 10)) {
121 /* Extra 16 bit shift to push mac address into
122 * high bits of uint64_t
124 mask
= htonll(0xffffffffffffULL
<< (16 + 48 - bits
));
125 memcpy(addr
, &mask
, ETH_ALEN
);
127 ret
= ll_addr_a2n(addr
, sizeof(addr
), slash
+ 1);
132 memset(addr
, 0xff, ETH_ALEN
);
134 addattr_l(n
, MAX_MSG
, mask_type
, addr
, sizeof(addr
));
143 static bool eth_type_vlan(__be16 ethertype
)
145 return ethertype
== htons(ETH_P_8021Q
) ||
146 ethertype
== htons(ETH_P_8021AD
);
149 static int flower_parse_vlan_eth_type(char *str
, __be16 eth_type
, int type
,
150 __be16
*p_vlan_eth_type
,
153 __be16 vlan_eth_type
;
155 if (!eth_type_vlan(eth_type
)) {
156 fprintf(stderr
, "Can't set \"%s\" if ethertype isn't 802.1Q or 802.1AD\n",
157 type
== TCA_FLOWER_KEY_VLAN_ETH_TYPE
? "vlan_ethtype" : "cvlan_ethtype");
161 if (ll_proto_a2n(&vlan_eth_type
, str
))
162 invarg("invalid vlan_ethtype", str
);
163 addattr16(n
, MAX_MSG
, type
, vlan_eth_type
);
164 *p_vlan_eth_type
= vlan_eth_type
;
168 struct flag_to_string
{
170 enum flower_matching_flags type
;
174 static struct flag_to_string flags_str
[] = {
175 { TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT
, FLOWER_IP_FLAGS
, "frag" },
176 { TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST
, FLOWER_IP_FLAGS
, "firstfrag" },
179 static int flower_parse_matching_flags(char *str
,
180 enum flower_matching_flags type
,
181 __u32
*mtf
, __u32
*mtf_mask
)
188 token
= strtok(str
, "/");
191 if (!strncmp(token
, "no", 2)) {
198 for (i
= 0; i
< ARRAY_SIZE(flags_str
); i
++) {
199 if (type
!= flags_str
[i
].type
)
202 if (!strcmp(token
, flags_str
[i
].string
)) {
204 *mtf
&= ~flags_str
[i
].flag
;
206 *mtf
|= flags_str
[i
].flag
;
208 *mtf_mask
|= flags_str
[i
].flag
;
216 token
= strtok(NULL
, "/");
222 static int flower_parse_u16(char *str
, int value_type
, int mask_type
,
228 slash
= strchr(str
, '/');
232 if (get_u16(&value
, str
, 0))
236 if (get_u16(&mask
, slash
+ 1, 0))
242 addattr16(n
, MAX_MSG
, value_type
, value
);
243 addattr16(n
, MAX_MSG
, mask_type
, mask
);
248 static int flower_parse_u32(char *str
, int value_type
, int mask_type
,
254 slash
= strchr(str
, '/');
258 if (get_u32(&value
, str
, 0))
262 if (get_u32(&mask
, slash
+ 1, 0))
268 addattr32(n
, MAX_MSG
, value_type
, value
);
269 addattr32(n
, MAX_MSG
, mask_type
, mask
);
274 static int flower_parse_ct_mark(char *str
, struct nlmsghdr
*n
)
276 return flower_parse_u32(str
,
277 TCA_FLOWER_KEY_CT_MARK
,
278 TCA_FLOWER_KEY_CT_MARK_MASK
,
282 static int flower_parse_ct_zone(char *str
, struct nlmsghdr
*n
)
284 return flower_parse_u16(str
,
285 TCA_FLOWER_KEY_CT_ZONE
,
286 TCA_FLOWER_KEY_CT_ZONE_MASK
,
290 static int flower_parse_ct_labels(char *str
, struct nlmsghdr
*n
)
292 #define LABELS_SIZE 16
293 uint8_t labels
[LABELS_SIZE
], lmask
[LABELS_SIZE
];
294 char *slash
, *mask
= NULL
;
295 size_t slen
, slen_mask
= 0;
297 slash
= index(str
, '/');
301 slen_mask
= strlen(mask
);
305 if (slen
> LABELS_SIZE
* 2 || slen_mask
> LABELS_SIZE
* 2) {
308 snprintf(errmsg
, sizeof(errmsg
),
309 "%zd Max allowed size %d",
310 slen
, LABELS_SIZE
*2);
314 if (hex2mem(str
, labels
, slen
/ 2) < 0)
315 invarg("labels must be a hex string\n", str
);
316 addattr_l(n
, MAX_MSG
, TCA_FLOWER_KEY_CT_LABELS
, labels
, slen
/ 2);
319 if (hex2mem(mask
, lmask
, slen_mask
/ 2) < 0)
320 invarg("labels mask must be a hex string\n", mask
);
322 memset(lmask
, 0xff, sizeof(lmask
));
323 slen_mask
= sizeof(lmask
) * 2;
325 addattr_l(n
, MAX_MSG
, TCA_FLOWER_KEY_CT_LABELS_MASK
, lmask
,
331 static struct flower_ct_states
{
334 } flower_ct_states
[] = {
335 { "trk", TCA_FLOWER_KEY_CT_FLAGS_TRACKED
},
336 { "new", TCA_FLOWER_KEY_CT_FLAGS_NEW
},
337 { "est", TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED
},
340 static int flower_parse_ct_state(char *str
, struct nlmsghdr
*n
)
342 int flags
= 0, mask
= 0, len
, i
;
345 while (*str
!= '\0') {
348 else if (*str
== '-')
353 for (i
= 0; i
< ARRAY_SIZE(flower_ct_states
); i
++) {
354 len
= strlen(flower_ct_states
[i
].str
);
355 if (strncmp(str
+ 1, flower_ct_states
[i
].str
, len
))
359 flags
|= flower_ct_states
[i
].flag
;
360 mask
|= flower_ct_states
[i
].flag
;
364 if (i
== ARRAY_SIZE(flower_ct_states
))
370 addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_CT_STATE
, flags
);
371 addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_CT_STATE_MASK
, mask
);
375 static int flower_parse_ip_proto(char *str
, __be16 eth_type
, int type
,
376 __u8
*p_ip_proto
, struct nlmsghdr
*n
)
381 if (eth_type
!= htons(ETH_P_IP
) && eth_type
!= htons(ETH_P_IPV6
))
384 if (matches(str
, "tcp") == 0) {
385 ip_proto
= IPPROTO_TCP
;
386 } else if (matches(str
, "udp") == 0) {
387 ip_proto
= IPPROTO_UDP
;
388 } else if (matches(str
, "sctp") == 0) {
389 ip_proto
= IPPROTO_SCTP
;
390 } else if (matches(str
, "icmp") == 0) {
391 if (eth_type
!= htons(ETH_P_IP
))
393 ip_proto
= IPPROTO_ICMP
;
394 } else if (matches(str
, "icmpv6") == 0) {
395 if (eth_type
!= htons(ETH_P_IPV6
))
397 ip_proto
= IPPROTO_ICMPV6
;
399 ret
= get_u8(&ip_proto
, str
, 16);
403 addattr8(n
, MAX_MSG
, type
, ip_proto
);
404 *p_ip_proto
= ip_proto
;
408 fprintf(stderr
, "Illegal \"eth_type\" for ip proto\n");
412 static int __flower_parse_ip_addr(char *str
, int family
,
413 int addr4_type
, int mask4_type
,
414 int addr6_type
, int mask6_type
,
422 ret
= get_prefix(&addr
, str
, family
);
426 if (family
&& (addr
.family
!= family
)) {
427 fprintf(stderr
, "Illegal \"eth_type\" for ip address\n");
431 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? addr4_type
: addr6_type
,
432 addr
.data
, addr
.bytelen
);
434 memset(addr
.data
, 0xff, addr
.bytelen
);
436 for (i
= 0; i
< addr
.bytelen
/ 4; i
++) {
439 } else if (bits
/ 32 >= 1) {
442 addr
.data
[i
] <<= 32 - bits
;
443 addr
.data
[i
] = htonl(addr
.data
[i
]);
448 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? mask4_type
: mask6_type
,
449 addr
.data
, addr
.bytelen
);
454 static int flower_parse_ip_addr(char *str
, __be16 eth_type
,
455 int addr4_type
, int mask4_type
,
456 int addr6_type
, int mask6_type
,
461 if (eth_type
== htons(ETH_P_IP
)) {
463 } else if (eth_type
== htons(ETH_P_IPV6
)) {
465 } else if (!eth_type
) {
471 return __flower_parse_ip_addr(str
, family
, addr4_type
, mask4_type
,
472 addr6_type
, mask6_type
, n
);
475 static bool flower_eth_type_arp(__be16 eth_type
)
477 return eth_type
== htons(ETH_P_ARP
) || eth_type
== htons(ETH_P_RARP
);
480 static int flower_parse_arp_ip_addr(char *str
, __be16 eth_type
,
481 int addr_type
, int mask_type
,
484 if (!flower_eth_type_arp(eth_type
))
487 return __flower_parse_ip_addr(str
, AF_INET
, addr_type
, mask_type
,
488 TCA_FLOWER_UNSPEC
, TCA_FLOWER_UNSPEC
, n
);
491 static int flower_parse_u8(char *str
, int value_type
, int mask_type
,
492 int (*value_from_name
)(const char *str
,
494 bool (*value_validate
)(__u8 value
),
501 slash
= strchr(str
, '/');
505 ret
= value_from_name
? value_from_name(str
, &value
) : -1;
507 ret
= get_u8(&value
, str
, 10);
512 if (value_validate
&& !value_validate(value
))
516 ret
= get_u8(&mask
, slash
+ 1, 10);
524 addattr8(n
, MAX_MSG
, value_type
, value
);
525 addattr8(n
, MAX_MSG
, mask_type
, mask
);
534 static const char *flower_print_arp_op_to_name(__u8 op
)
546 static int flower_arp_op_from_name(const char *name
, __u8
*op
)
548 if (!strcmp(name
, "request"))
550 else if (!strcmp(name
, "reply"))
558 static bool flow_arp_op_validate(__u8 op
)
560 return !op
|| op
== ARPOP_REQUEST
|| op
== ARPOP_REPLY
;
563 static int flower_parse_arp_op(char *str
, __be16 eth_type
,
564 int op_type
, int mask_type
,
567 if (!flower_eth_type_arp(eth_type
))
570 return flower_parse_u8(str
, op_type
, mask_type
, flower_arp_op_from_name
,
571 flow_arp_op_validate
, n
);
574 static int flower_icmp_attr_type(__be16 eth_type
, __u8 ip_proto
,
575 enum flower_icmp_field field
)
577 if (eth_type
== htons(ETH_P_IP
) && ip_proto
== IPPROTO_ICMP
)
578 return field
== FLOWER_ICMP_FIELD_CODE
?
579 TCA_FLOWER_KEY_ICMPV4_CODE
:
580 TCA_FLOWER_KEY_ICMPV4_TYPE
;
581 else if (eth_type
== htons(ETH_P_IPV6
) && ip_proto
== IPPROTO_ICMPV6
)
582 return field
== FLOWER_ICMP_FIELD_CODE
?
583 TCA_FLOWER_KEY_ICMPV6_CODE
:
584 TCA_FLOWER_KEY_ICMPV6_TYPE
;
589 static int flower_icmp_attr_mask_type(__be16 eth_type
, __u8 ip_proto
,
590 enum flower_icmp_field field
)
592 if (eth_type
== htons(ETH_P_IP
) && ip_proto
== IPPROTO_ICMP
)
593 return field
== FLOWER_ICMP_FIELD_CODE
?
594 TCA_FLOWER_KEY_ICMPV4_CODE_MASK
:
595 TCA_FLOWER_KEY_ICMPV4_TYPE_MASK
;
596 else if (eth_type
== htons(ETH_P_IPV6
) && ip_proto
== IPPROTO_ICMPV6
)
597 return field
== FLOWER_ICMP_FIELD_CODE
?
598 TCA_FLOWER_KEY_ICMPV6_CODE_MASK
:
599 TCA_FLOWER_KEY_ICMPV6_TYPE_MASK
;
604 static int flower_parse_icmp(char *str
, __u16 eth_type
, __u8 ip_proto
,
605 enum flower_icmp_field field
, struct nlmsghdr
*n
)
607 int value_type
, mask_type
;
609 value_type
= flower_icmp_attr_type(eth_type
, ip_proto
, field
);
610 mask_type
= flower_icmp_attr_mask_type(eth_type
, ip_proto
, field
);
611 if (value_type
< 0 || mask_type
< 0)
614 return flower_parse_u8(str
, value_type
, mask_type
, NULL
, NULL
, n
);
617 static int flower_port_attr_type(__u8 ip_proto
, enum flower_endpoint endpoint
)
619 if (ip_proto
== IPPROTO_TCP
)
620 return endpoint
== FLOWER_ENDPOINT_SRC
?
621 TCA_FLOWER_KEY_TCP_SRC
:
622 TCA_FLOWER_KEY_TCP_DST
;
623 else if (ip_proto
== IPPROTO_UDP
)
624 return endpoint
== FLOWER_ENDPOINT_SRC
?
625 TCA_FLOWER_KEY_UDP_SRC
:
626 TCA_FLOWER_KEY_UDP_DST
;
627 else if (ip_proto
== IPPROTO_SCTP
)
628 return endpoint
== FLOWER_ENDPOINT_SRC
?
629 TCA_FLOWER_KEY_SCTP_SRC
:
630 TCA_FLOWER_KEY_SCTP_DST
;
635 static int flower_port_range_attr_type(__u8 ip_proto
, enum flower_endpoint type
,
636 __be16
*min_port_type
,
637 __be16
*max_port_type
)
639 if (ip_proto
== IPPROTO_TCP
|| ip_proto
== IPPROTO_UDP
||
640 ip_proto
== IPPROTO_SCTP
) {
641 if (type
== FLOWER_ENDPOINT_SRC
) {
642 *min_port_type
= TCA_FLOWER_KEY_PORT_SRC_MIN
;
643 *max_port_type
= TCA_FLOWER_KEY_PORT_SRC_MAX
;
645 *min_port_type
= TCA_FLOWER_KEY_PORT_DST_MIN
;
646 *max_port_type
= TCA_FLOWER_KEY_PORT_DST_MAX
;
654 /* parse range args in format 10-20 */
655 static int parse_range(char *str
, __be16
*min
, __be16
*max
)
659 sep
= strchr(str
, '-');
663 if (get_be16(min
, str
, 10))
666 if (get_be16(max
, sep
+ 1, 10))
669 if (get_be16(min
, str
, 10))
675 static int flower_parse_port(char *str
, __u8 ip_proto
,
676 enum flower_endpoint endpoint
,
683 ret
= parse_range(str
, &min
, &max
);
688 __be16 min_port_type
, max_port_type
;
691 fprintf(stderr
, "max value should be greater than min value\n");
694 if (flower_port_range_attr_type(ip_proto
, endpoint
,
695 &min_port_type
, &max_port_type
))
698 addattr16(n
, MAX_MSG
, min_port_type
, min
);
699 addattr16(n
, MAX_MSG
, max_port_type
, max
);
700 } else if (min
&& !max
) {
703 type
= flower_port_attr_type(ip_proto
, endpoint
);
706 addattr16(n
, MAX_MSG
, type
, min
);
713 #define TCP_FLAGS_MAX_MASK 0xfff
715 static int flower_parse_tcp_flags(char *str
, int flags_type
, int mask_type
,
722 slash
= strchr(str
, '/');
726 ret
= get_u16(&flags
, str
, 16);
727 if (ret
< 0 || flags
& ~TCP_FLAGS_MAX_MASK
)
730 addattr16(n
, MAX_MSG
, flags_type
, htons(flags
));
733 ret
= get_u16(&flags
, slash
+ 1, 16);
734 if (ret
< 0 || flags
& ~TCP_FLAGS_MAX_MASK
)
737 flags
= TCP_FLAGS_MAX_MASK
;
739 addattr16(n
, MAX_MSG
, mask_type
, htons(flags
));
748 static int flower_parse_ip_tos_ttl(char *str
, int key_type
, int mask_type
,
755 slash
= strchr(str
, '/');
759 ret
= get_u8(&tos_ttl
, str
, 10);
761 ret
= get_u8(&tos_ttl
, str
, 16);
765 addattr8(n
, MAX_MSG
, key_type
, tos_ttl
);
768 ret
= get_u8(&tos_ttl
, slash
+ 1, 16);
774 addattr8(n
, MAX_MSG
, mask_type
, tos_ttl
);
783 static int flower_parse_key_id(const char *str
, int type
, struct nlmsghdr
*n
)
788 ret
= get_be32(&key_id
, str
, 10);
790 addattr32(n
, MAX_MSG
, type
, key_id
);
795 static int flower_parse_enc_port(char *str
, int type
, struct nlmsghdr
*n
)
800 ret
= get_be16(&port
, str
, 10);
804 addattr16(n
, MAX_MSG
, type
, port
);
809 static int flower_parse_geneve_opts(char *str
, struct nlmsghdr
*n
)
815 nest
= addattr_nest(n
, MAX_MSG
, TCA_FLOWER_KEY_ENC_OPTS_GENEVE
);
818 token
= strsep(&str
, ":");
821 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
:
827 err
= get_be16(&opt_class
, token
, 16);
831 addattr16(n
, MAX_MSG
, i
, opt_class
);
834 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
:
840 err
= get_u8(&opt_type
, token
, 16);
844 addattr8(n
, MAX_MSG
, i
, opt_type
);
847 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
:
849 size_t token_len
= strlen(token
);
854 opts
= malloc(token_len
/ 2);
857 if (hex2mem(token
, opts
, token_len
/ 2) < 0) {
861 addattr_l(n
, MAX_MSG
, i
, opts
, token_len
/ 2);
867 fprintf(stderr
, "Unknown \"geneve_opts\" type\n");
871 token
= strsep(&str
, ":");
874 addattr_nest_end(n
, nest
);
879 static int flower_parse_enc_opt_part(char *str
, struct nlmsghdr
*n
)
884 token
= strsep(&str
, ",");
886 err
= flower_parse_geneve_opts(token
, n
);
890 token
= strsep(&str
, ",");
896 static int flower_check_enc_opt_key(char *key
)
898 int key_len
, col_cnt
= 0;
900 key_len
= strlen(key
);
901 while ((key
= strchr(key
, ':'))) {
902 if (strlen(key
) == key_len
)
905 key_len
= strlen(key
) - 1;
910 if (col_cnt
!= 2 || !key_len
)
916 static int flower_parse_enc_opts(char *str
, struct nlmsghdr
*n
)
918 char key
[XATTR_SIZE_MAX
], mask
[XATTR_SIZE_MAX
];
919 int data_len
, key_len
, mask_len
, err
;
925 token
= strsep(&str
, ",");
927 slash
= strchr(token
, '/');
931 if ((key_len
+ strlen(token
) > XATTR_SIZE_MAX
) ||
932 flower_check_enc_opt_key(token
))
935 strcpy(&key
[key_len
], token
);
936 key_len
+= strlen(token
) + 1;
937 key
[key_len
- 1] = ',';
940 /* Pad out mask when not provided */
941 if (mask_len
+ strlen(token
) > XATTR_SIZE_MAX
)
944 data_len
= strlen(rindex(token
, ':'));
945 sprintf(&mask
[mask_len
], "ffff:ff:");
947 memset(&mask
[mask_len
], 'f', data_len
- 1);
948 mask_len
+= data_len
;
949 mask
[mask_len
- 1] = ',';
950 token
= strsep(&str
, ",");
954 if (mask_len
+ strlen(slash
+ 1) > XATTR_SIZE_MAX
)
957 strcpy(&mask
[mask_len
], slash
+ 1);
958 mask_len
+= strlen(slash
+ 1) + 1;
959 mask
[mask_len
- 1] = ',';
962 token
= strsep(&str
, ",");
964 key
[key_len
- 1] = '\0';
965 mask
[mask_len
- 1] = '\0';
967 nest
= addattr_nest(n
, MAX_MSG
, TCA_FLOWER_KEY_ENC_OPTS
);
968 err
= flower_parse_enc_opt_part(key
, n
);
971 addattr_nest_end(n
, nest
);
973 nest
= addattr_nest(n
, MAX_MSG
, TCA_FLOWER_KEY_ENC_OPTS_MASK
);
974 err
= flower_parse_enc_opt_part(mask
, n
);
977 addattr_nest_end(n
, nest
);
982 static int flower_parse_opt(struct filter_util
*qu
, char *handle
,
983 int argc
, char **argv
, struct nlmsghdr
*n
)
986 struct tcmsg
*t
= NLMSG_DATA(n
);
988 __be16 eth_type
= TC_H_MIN(t
->tcm_info
);
989 __be16 vlan_ethtype
= 0;
990 __be16 cvlan_ethtype
= 0;
991 __u8 ip_proto
= 0xff;
997 ret
= get_u32(&t
->tcm_handle
, handle
, 0);
999 fprintf(stderr
, "Illegal \"handle\"\n");
1004 tail
= (struct rtattr
*) (((void *) n
) + NLMSG_ALIGN(n
->nlmsg_len
));
1005 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
1008 /*at minimal we will match all ethertype packets */
1013 if (matches(*argv
, "classid") == 0 ||
1014 matches(*argv
, "flowid") == 0) {
1015 unsigned int handle
;
1018 ret
= get_tc_classid(&handle
, *argv
);
1020 fprintf(stderr
, "Illegal \"classid\"\n");
1023 addattr_l(n
, MAX_MSG
, TCA_FLOWER_CLASSID
, &handle
, 4);
1024 } else if (matches(*argv
, "hw_tc") == 0) {
1025 unsigned int handle
;
1030 tc
= strtoul(*argv
, &end
, 0);
1032 fprintf(stderr
, "Illegal TC index\n");
1035 if (tc
>= TC_QOPT_MAX_QUEUE
) {
1036 fprintf(stderr
, "TC index exceeds max range\n");
1039 handle
= TC_H_MAKE(TC_H_MAJ(t
->tcm_parent
),
1040 TC_H_MIN(tc
+ TC_H_MIN_PRIORITY
));
1041 addattr_l(n
, MAX_MSG
, TCA_FLOWER_CLASSID
, &handle
,
1043 } else if (matches(*argv
, "ip_flags") == 0) {
1045 ret
= flower_parse_matching_flags(*argv
,
1050 fprintf(stderr
, "Illegal \"ip_flags\"\n");
1053 } else if (matches(*argv
, "verbose") == 0) {
1054 flags
|= TCA_CLS_FLAGS_VERBOSE
;
1055 } else if (matches(*argv
, "skip_hw") == 0) {
1056 flags
|= TCA_CLS_FLAGS_SKIP_HW
;
1057 } else if (matches(*argv
, "skip_sw") == 0) {
1058 flags
|= TCA_CLS_FLAGS_SKIP_SW
;
1059 } else if (matches(*argv
, "ct_state") == 0) {
1061 ret
= flower_parse_ct_state(*argv
, n
);
1063 fprintf(stderr
, "Illegal \"ct_state\"\n");
1066 } else if (matches(*argv
, "ct_zone") == 0) {
1068 ret
= flower_parse_ct_zone(*argv
, n
);
1070 fprintf(stderr
, "Illegal \"ct_zone\"\n");
1073 } else if (matches(*argv
, "ct_mark") == 0) {
1075 ret
= flower_parse_ct_mark(*argv
, n
);
1077 fprintf(stderr
, "Illegal \"ct_mark\"\n");
1080 } else if (matches(*argv
, "ct_label") == 0) {
1082 ret
= flower_parse_ct_labels(*argv
, n
);
1084 fprintf(stderr
, "Illegal \"ct_label\"\n");
1087 } else if (matches(*argv
, "indev") == 0) {
1089 if (check_ifname(*argv
))
1090 invarg("\"indev\" not a valid ifname", *argv
);
1091 addattrstrz(n
, MAX_MSG
, TCA_FLOWER_INDEV
, *argv
);
1092 } else if (matches(*argv
, "vlan_id") == 0) {
1096 if (!eth_type_vlan(eth_type
)) {
1097 fprintf(stderr
, "Can't set \"vlan_id\" if ethertype isn't 802.1Q or 802.1AD\n");
1100 ret
= get_u16(&vid
, *argv
, 10);
1101 if (ret
< 0 || vid
& ~0xfff) {
1102 fprintf(stderr
, "Illegal \"vlan_id\"\n");
1105 addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_VLAN_ID
, vid
);
1106 } else if (matches(*argv
, "vlan_prio") == 0) {
1110 if (!eth_type_vlan(eth_type
)) {
1111 fprintf(stderr
, "Can't set \"vlan_prio\" if ethertype isn't 802.1Q or 802.1AD\n");
1114 ret
= get_u8(&vlan_prio
, *argv
, 10);
1115 if (ret
< 0 || vlan_prio
& ~0x7) {
1116 fprintf(stderr
, "Illegal \"vlan_prio\"\n");
1119 addattr8(n
, MAX_MSG
,
1120 TCA_FLOWER_KEY_VLAN_PRIO
, vlan_prio
);
1121 } else if (matches(*argv
, "vlan_ethtype") == 0) {
1123 ret
= flower_parse_vlan_eth_type(*argv
, eth_type
,
1124 TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
1128 } else if (matches(*argv
, "cvlan_id") == 0) {
1132 if (!eth_type_vlan(vlan_ethtype
)) {
1133 fprintf(stderr
, "Can't set \"cvlan_id\" if inner vlan ethertype isn't 802.1Q or 802.1AD\n");
1136 ret
= get_u16(&vid
, *argv
, 10);
1137 if (ret
< 0 || vid
& ~0xfff) {
1138 fprintf(stderr
, "Illegal \"cvlan_id\"\n");
1141 addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_CVLAN_ID
, vid
);
1142 } else if (matches(*argv
, "cvlan_prio") == 0) {
1146 if (!eth_type_vlan(vlan_ethtype
)) {
1147 fprintf(stderr
, "Can't set \"cvlan_prio\" if inner vlan ethertype isn't 802.1Q or 802.1AD\n");
1150 ret
= get_u8(&cvlan_prio
, *argv
, 10);
1151 if (ret
< 0 || cvlan_prio
& ~0x7) {
1152 fprintf(stderr
, "Illegal \"cvlan_prio\"\n");
1155 addattr8(n
, MAX_MSG
,
1156 TCA_FLOWER_KEY_CVLAN_PRIO
, cvlan_prio
);
1157 } else if (matches(*argv
, "cvlan_ethtype") == 0) {
1159 ret
= flower_parse_vlan_eth_type(*argv
, vlan_ethtype
,
1160 TCA_FLOWER_KEY_CVLAN_ETH_TYPE
,
1164 } else if (matches(*argv
, "mpls_label") == 0) {
1168 if (eth_type
!= htons(ETH_P_MPLS_UC
) &&
1169 eth_type
!= htons(ETH_P_MPLS_MC
)) {
1171 "Can't set \"mpls_label\" if ethertype isn't MPLS\n");
1174 ret
= get_u32(&label
, *argv
, 10);
1175 if (ret
< 0 || label
& ~(MPLS_LS_LABEL_MASK
>> MPLS_LS_LABEL_SHIFT
)) {
1176 fprintf(stderr
, "Illegal \"mpls_label\"\n");
1179 addattr32(n
, MAX_MSG
, TCA_FLOWER_KEY_MPLS_LABEL
, label
);
1180 } else if (matches(*argv
, "mpls_tc") == 0) {
1184 if (eth_type
!= htons(ETH_P_MPLS_UC
) &&
1185 eth_type
!= htons(ETH_P_MPLS_MC
)) {
1187 "Can't set \"mpls_tc\" if ethertype isn't MPLS\n");
1190 ret
= get_u8(&tc
, *argv
, 10);
1191 if (ret
< 0 || tc
& ~(MPLS_LS_TC_MASK
>> MPLS_LS_TC_SHIFT
)) {
1192 fprintf(stderr
, "Illegal \"mpls_tc\"\n");
1195 addattr8(n
, MAX_MSG
, TCA_FLOWER_KEY_MPLS_TC
, tc
);
1196 } else if (matches(*argv
, "mpls_bos") == 0) {
1200 if (eth_type
!= htons(ETH_P_MPLS_UC
) &&
1201 eth_type
!= htons(ETH_P_MPLS_MC
)) {
1203 "Can't set \"mpls_bos\" if ethertype isn't MPLS\n");
1206 ret
= get_u8(&bos
, *argv
, 10);
1207 if (ret
< 0 || bos
& ~(MPLS_LS_S_MASK
>> MPLS_LS_S_SHIFT
)) {
1208 fprintf(stderr
, "Illegal \"mpls_bos\"\n");
1211 addattr8(n
, MAX_MSG
, TCA_FLOWER_KEY_MPLS_BOS
, bos
);
1212 } else if (matches(*argv
, "mpls_ttl") == 0) {
1216 if (eth_type
!= htons(ETH_P_MPLS_UC
) &&
1217 eth_type
!= htons(ETH_P_MPLS_MC
)) {
1219 "Can't set \"mpls_ttl\" if ethertype isn't MPLS\n");
1222 ret
= get_u8(&ttl
, *argv
, 10);
1223 if (ret
< 0 || ttl
& ~(MPLS_LS_TTL_MASK
>> MPLS_LS_TTL_SHIFT
)) {
1224 fprintf(stderr
, "Illegal \"mpls_ttl\"\n");
1227 addattr8(n
, MAX_MSG
, TCA_FLOWER_KEY_MPLS_TTL
, ttl
);
1228 } else if (matches(*argv
, "dst_mac") == 0) {
1230 ret
= flower_parse_eth_addr(*argv
,
1231 TCA_FLOWER_KEY_ETH_DST
,
1232 TCA_FLOWER_KEY_ETH_DST_MASK
,
1235 fprintf(stderr
, "Illegal \"dst_mac\"\n");
1238 } else if (matches(*argv
, "src_mac") == 0) {
1240 ret
= flower_parse_eth_addr(*argv
,
1241 TCA_FLOWER_KEY_ETH_SRC
,
1242 TCA_FLOWER_KEY_ETH_SRC_MASK
,
1245 fprintf(stderr
, "Illegal \"src_mac\"\n");
1248 } else if (matches(*argv
, "ip_proto") == 0) {
1250 ret
= flower_parse_ip_proto(*argv
, cvlan_ethtype
?
1251 cvlan_ethtype
: vlan_ethtype
?
1252 vlan_ethtype
: eth_type
,
1253 TCA_FLOWER_KEY_IP_PROTO
,
1256 fprintf(stderr
, "Illegal \"ip_proto\"\n");
1259 } else if (matches(*argv
, "ip_tos") == 0) {
1261 ret
= flower_parse_ip_tos_ttl(*argv
,
1262 TCA_FLOWER_KEY_IP_TOS
,
1263 TCA_FLOWER_KEY_IP_TOS_MASK
,
1266 fprintf(stderr
, "Illegal \"ip_tos\"\n");
1269 } else if (matches(*argv
, "ip_ttl") == 0) {
1271 ret
= flower_parse_ip_tos_ttl(*argv
,
1272 TCA_FLOWER_KEY_IP_TTL
,
1273 TCA_FLOWER_KEY_IP_TTL_MASK
,
1276 fprintf(stderr
, "Illegal \"ip_ttl\"\n");
1279 } else if (matches(*argv
, "dst_ip") == 0) {
1281 ret
= flower_parse_ip_addr(*argv
, cvlan_ethtype
?
1282 cvlan_ethtype
: vlan_ethtype
?
1283 vlan_ethtype
: eth_type
,
1284 TCA_FLOWER_KEY_IPV4_DST
,
1285 TCA_FLOWER_KEY_IPV4_DST_MASK
,
1286 TCA_FLOWER_KEY_IPV6_DST
,
1287 TCA_FLOWER_KEY_IPV6_DST_MASK
,
1290 fprintf(stderr
, "Illegal \"dst_ip\"\n");
1293 } else if (matches(*argv
, "src_ip") == 0) {
1295 ret
= flower_parse_ip_addr(*argv
, cvlan_ethtype
?
1296 cvlan_ethtype
: vlan_ethtype
?
1297 vlan_ethtype
: eth_type
,
1298 TCA_FLOWER_KEY_IPV4_SRC
,
1299 TCA_FLOWER_KEY_IPV4_SRC_MASK
,
1300 TCA_FLOWER_KEY_IPV6_SRC
,
1301 TCA_FLOWER_KEY_IPV6_SRC_MASK
,
1304 fprintf(stderr
, "Illegal \"src_ip\"\n");
1307 } else if (matches(*argv
, "dst_port") == 0) {
1309 ret
= flower_parse_port(*argv
, ip_proto
,
1310 FLOWER_ENDPOINT_DST
, n
);
1312 fprintf(stderr
, "Illegal \"dst_port\"\n");
1315 } else if (matches(*argv
, "src_port") == 0) {
1317 ret
= flower_parse_port(*argv
, ip_proto
,
1318 FLOWER_ENDPOINT_SRC
, n
);
1320 fprintf(stderr
, "Illegal \"src_port\"\n");
1323 } else if (matches(*argv
, "tcp_flags") == 0) {
1325 ret
= flower_parse_tcp_flags(*argv
,
1326 TCA_FLOWER_KEY_TCP_FLAGS
,
1327 TCA_FLOWER_KEY_TCP_FLAGS_MASK
,
1330 fprintf(stderr
, "Illegal \"tcp_flags\"\n");
1333 } else if (matches(*argv
, "type") == 0) {
1335 ret
= flower_parse_icmp(*argv
, eth_type
, ip_proto
,
1336 FLOWER_ICMP_FIELD_TYPE
, n
);
1338 fprintf(stderr
, "Illegal \"icmp type\"\n");
1341 } else if (matches(*argv
, "code") == 0) {
1343 ret
= flower_parse_icmp(*argv
, eth_type
, ip_proto
,
1344 FLOWER_ICMP_FIELD_CODE
, n
);
1346 fprintf(stderr
, "Illegal \"icmp code\"\n");
1349 } else if (matches(*argv
, "arp_tip") == 0) {
1351 ret
= flower_parse_arp_ip_addr(*argv
, vlan_ethtype
?
1352 vlan_ethtype
: eth_type
,
1353 TCA_FLOWER_KEY_ARP_TIP
,
1354 TCA_FLOWER_KEY_ARP_TIP_MASK
,
1357 fprintf(stderr
, "Illegal \"arp_tip\"\n");
1360 } else if (matches(*argv
, "arp_sip") == 0) {
1362 ret
= flower_parse_arp_ip_addr(*argv
, vlan_ethtype
?
1363 vlan_ethtype
: eth_type
,
1364 TCA_FLOWER_KEY_ARP_SIP
,
1365 TCA_FLOWER_KEY_ARP_SIP_MASK
,
1368 fprintf(stderr
, "Illegal \"arp_sip\"\n");
1371 } else if (matches(*argv
, "arp_op") == 0) {
1373 ret
= flower_parse_arp_op(*argv
, vlan_ethtype
?
1374 vlan_ethtype
: eth_type
,
1375 TCA_FLOWER_KEY_ARP_OP
,
1376 TCA_FLOWER_KEY_ARP_OP_MASK
,
1379 fprintf(stderr
, "Illegal \"arp_op\"\n");
1382 } else if (matches(*argv
, "arp_tha") == 0) {
1384 ret
= flower_parse_eth_addr(*argv
,
1385 TCA_FLOWER_KEY_ARP_THA
,
1386 TCA_FLOWER_KEY_ARP_THA_MASK
,
1389 fprintf(stderr
, "Illegal \"arp_tha\"\n");
1392 } else if (matches(*argv
, "arp_sha") == 0) {
1394 ret
= flower_parse_eth_addr(*argv
,
1395 TCA_FLOWER_KEY_ARP_SHA
,
1396 TCA_FLOWER_KEY_ARP_SHA_MASK
,
1399 fprintf(stderr
, "Illegal \"arp_sha\"\n");
1402 } else if (matches(*argv
, "enc_dst_ip") == 0) {
1404 ret
= flower_parse_ip_addr(*argv
, 0,
1405 TCA_FLOWER_KEY_ENC_IPV4_DST
,
1406 TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
,
1407 TCA_FLOWER_KEY_ENC_IPV6_DST
,
1408 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
,
1411 fprintf(stderr
, "Illegal \"enc_dst_ip\"\n");
1414 } else if (matches(*argv
, "enc_src_ip") == 0) {
1416 ret
= flower_parse_ip_addr(*argv
, 0,
1417 TCA_FLOWER_KEY_ENC_IPV4_SRC
,
1418 TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
,
1419 TCA_FLOWER_KEY_ENC_IPV6_SRC
,
1420 TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
,
1423 fprintf(stderr
, "Illegal \"enc_src_ip\"\n");
1426 } else if (matches(*argv
, "enc_key_id") == 0) {
1428 ret
= flower_parse_key_id(*argv
,
1429 TCA_FLOWER_KEY_ENC_KEY_ID
, n
);
1431 fprintf(stderr
, "Illegal \"enc_key_id\"\n");
1434 } else if (matches(*argv
, "enc_dst_port") == 0) {
1436 ret
= flower_parse_enc_port(*argv
,
1437 TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, n
);
1439 fprintf(stderr
, "Illegal \"enc_dst_port\"\n");
1442 } else if (matches(*argv
, "enc_tos") == 0) {
1444 ret
= flower_parse_ip_tos_ttl(*argv
,
1445 TCA_FLOWER_KEY_ENC_IP_TOS
,
1446 TCA_FLOWER_KEY_ENC_IP_TOS_MASK
,
1449 fprintf(stderr
, "Illegal \"enc_tos\"\n");
1452 } else if (matches(*argv
, "enc_ttl") == 0) {
1454 ret
= flower_parse_ip_tos_ttl(*argv
,
1455 TCA_FLOWER_KEY_ENC_IP_TTL
,
1456 TCA_FLOWER_KEY_ENC_IP_TTL_MASK
,
1459 fprintf(stderr
, "Illegal \"enc_ttl\"\n");
1462 } else if (matches(*argv
, "geneve_opts") == 0) {
1464 ret
= flower_parse_enc_opts(*argv
, n
);
1466 fprintf(stderr
, "Illegal \"geneve_opts\"\n");
1469 } else if (matches(*argv
, "action") == 0) {
1471 ret
= parse_action(&argc
, &argv
, TCA_FLOWER_ACT
, n
);
1473 fprintf(stderr
, "Illegal \"action\"\n");
1477 } else if (strcmp(*argv
, "help") == 0) {
1481 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
1489 ret
= addattr32(n
, MAX_MSG
, TCA_FLOWER_FLAGS
, flags
);
1494 ret
= addattr32(n
, MAX_MSG
, TCA_FLOWER_KEY_FLAGS
, htonl(mtf
));
1498 ret
= addattr32(n
, MAX_MSG
, TCA_FLOWER_KEY_FLAGS_MASK
, htonl(mtf_mask
));
1503 if (eth_type
!= htons(ETH_P_ALL
)) {
1504 ret
= addattr16(n
, MAX_MSG
, TCA_FLOWER_KEY_ETH_TYPE
, eth_type
);
1509 tail
->rta_len
= (((void *)n
)+n
->nlmsg_len
) - (void *)tail
;
1514 static int __mask_bits(char *addr
, size_t len
)
1521 for (i
= 0; i
< len
; i
++, addr
++) {
1522 for (j
= 7; j
>= 0; j
--) {
1523 if (((*addr
) >> j
) & 0x1) {
1537 static void flower_print_eth_addr(char *name
, struct rtattr
*addr_attr
,
1538 struct rtattr
*mask_attr
)
1540 SPRINT_BUF(namefrm
);
1546 if (!addr_attr
|| RTA_PAYLOAD(addr_attr
) != ETH_ALEN
)
1548 done
= sprintf(out
, "%s",
1549 ll_addr_n2a(RTA_DATA(addr_attr
), ETH_ALEN
,
1550 0, b1
, sizeof(b1
)));
1551 if (mask_attr
&& RTA_PAYLOAD(mask_attr
) == ETH_ALEN
) {
1552 bits
= __mask_bits(RTA_DATA(mask_attr
), ETH_ALEN
);
1554 sprintf(out
+ done
, "/%s",
1555 ll_addr_n2a(RTA_DATA(mask_attr
), ETH_ALEN
,
1556 0, b1
, sizeof(b1
)));
1557 else if (bits
< ETH_ALEN
* 8)
1558 sprintf(out
+ done
, "/%d", bits
);
1561 sprintf(namefrm
, "\n %s %%s", name
);
1562 print_string(PRINT_ANY
, name
, namefrm
, out
);
1565 static void flower_print_eth_type(__be16
*p_eth_type
,
1566 struct rtattr
*eth_type_attr
)
1574 eth_type
= rta_getattr_u16(eth_type_attr
);
1575 if (eth_type
== htons(ETH_P_IP
))
1576 sprintf(out
, "ipv4");
1577 else if (eth_type
== htons(ETH_P_IPV6
))
1578 sprintf(out
, "ipv6");
1579 else if (eth_type
== htons(ETH_P_ARP
))
1580 sprintf(out
, "arp");
1581 else if (eth_type
== htons(ETH_P_RARP
))
1582 sprintf(out
, "rarp");
1584 sprintf(out
, "%04x", ntohs(eth_type
));
1586 print_string(PRINT_ANY
, "eth_type", "\n eth_type %s", out
);
1587 *p_eth_type
= eth_type
;
1590 static void flower_print_ip_proto(__u8
*p_ip_proto
,
1591 struct rtattr
*ip_proto_attr
)
1599 ip_proto
= rta_getattr_u8(ip_proto_attr
);
1600 if (ip_proto
== IPPROTO_TCP
)
1601 sprintf(out
, "tcp");
1602 else if (ip_proto
== IPPROTO_UDP
)
1603 sprintf(out
, "udp");
1604 else if (ip_proto
== IPPROTO_SCTP
)
1605 sprintf(out
, "sctp");
1606 else if (ip_proto
== IPPROTO_ICMP
)
1607 sprintf(out
, "icmp");
1608 else if (ip_proto
== IPPROTO_ICMPV6
)
1609 sprintf(out
, "icmpv6");
1611 sprintf(out
, "%02x", ip_proto
);
1613 print_string(PRINT_ANY
, "ip_proto", "\n ip_proto %s", out
);
1614 *p_ip_proto
= ip_proto
;
1617 static void flower_print_ip_attr(const char *name
, struct rtattr
*key_attr
,
1618 struct rtattr
*mask_attr
)
1620 SPRINT_BUF(namefrm
);
1627 done
= sprintf(out
, "0x%x", rta_getattr_u8(key_attr
));
1629 sprintf(out
+ done
, "/%x", rta_getattr_u8(mask_attr
));
1631 print_string(PRINT_FP
, NULL
, "%s ", _SL_
);
1632 sprintf(namefrm
, "%s %%s", name
);
1633 print_string(PRINT_ANY
, name
, namefrm
, out
);
1636 static void flower_print_matching_flags(char *name
,
1637 enum flower_matching_flags type
,
1638 struct rtattr
*attr
,
1639 struct rtattr
*mask_attr
)
1646 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != 4)
1649 mtf
= ntohl(rta_getattr_u32(attr
));
1650 mtf_mask
= ntohl(rta_getattr_u32(mask_attr
));
1652 for (i
= 0; i
< ARRAY_SIZE(flags_str
); i
++) {
1653 if (type
!= flags_str
[i
].type
)
1655 if (mtf_mask
& flags_str
[i
].flag
) {
1657 print_string(PRINT_FP
, NULL
, "\n %s ", name
);
1658 open_json_object(name
);
1660 print_string(PRINT_FP
, NULL
, "/", NULL
);
1663 print_bool(PRINT_JSON
, flags_str
[i
].string
, NULL
,
1664 mtf
& flags_str
[i
].flag
);
1665 if (mtf
& flags_str
[i
].flag
)
1666 print_string(PRINT_FP
, NULL
, "%s",
1667 flags_str
[i
].string
);
1669 print_string(PRINT_FP
, NULL
, "no%s",
1670 flags_str
[i
].string
);
1674 close_json_object();
1677 static void flower_print_ip_addr(char *name
, __be16 eth_type
,
1678 struct rtattr
*addr4_attr
,
1679 struct rtattr
*mask4_attr
,
1680 struct rtattr
*addr6_attr
,
1681 struct rtattr
*mask6_attr
)
1683 struct rtattr
*addr_attr
;
1684 struct rtattr
*mask_attr
;
1685 SPRINT_BUF(namefrm
);
1692 if (eth_type
== htons(ETH_P_IP
)) {
1694 addr_attr
= addr4_attr
;
1695 mask_attr
= mask4_attr
;
1697 } else if (eth_type
== htons(ETH_P_IPV6
)) {
1699 addr_attr
= addr6_attr
;
1700 mask_attr
= mask6_attr
;
1705 if (!addr_attr
|| RTA_PAYLOAD(addr_attr
) != len
)
1707 if (!mask_attr
|| RTA_PAYLOAD(mask_attr
) != len
)
1709 done
= sprintf(out
, "%s", rt_addr_n2a_rta(family
, addr_attr
));
1710 bits
= __mask_bits(RTA_DATA(mask_attr
), len
);
1712 sprintf(out
+ done
, "/%s", rt_addr_n2a_rta(family
, mask_attr
));
1713 else if (bits
< len
* 8)
1714 sprintf(out
+ done
, "/%d", bits
);
1716 sprintf(namefrm
, "\n %s %%s", name
);
1717 print_string(PRINT_ANY
, name
, namefrm
, out
);
1719 static void flower_print_ip4_addr(char *name
, struct rtattr
*addr_attr
,
1720 struct rtattr
*mask_attr
)
1722 return flower_print_ip_addr(name
, htons(ETH_P_IP
),
1723 addr_attr
, mask_attr
, 0, 0);
1726 static void flower_print_port(char *name
, struct rtattr
*attr
)
1728 SPRINT_BUF(namefrm
);
1733 sprintf(namefrm
,"\n %s %%u", name
);
1734 print_hu(PRINT_ANY
, name
, namefrm
, rta_getattr_be16(attr
));
1737 static void flower_print_port_range(char *name
, struct rtattr
*min_attr
,
1738 struct rtattr
*max_attr
)
1740 if (!min_attr
|| !max_attr
)
1743 if (is_json_context()) {
1744 open_json_object(name
);
1745 print_hu(PRINT_JSON
, "start", NULL
, rta_getattr_be16(min_attr
));
1746 print_hu(PRINT_JSON
, "end", NULL
, rta_getattr_be16(max_attr
));
1747 close_json_object();
1749 SPRINT_BUF(namefrm
);
1753 done
= sprintf(out
, "%u", rta_getattr_be16(min_attr
));
1754 sprintf(out
+ done
, "-%u", rta_getattr_be16(max_attr
));
1755 sprintf(namefrm
, "\n %s %%s", name
);
1756 print_string(PRINT_ANY
, name
, namefrm
, out
);
1760 static void flower_print_tcp_flags(const char *name
, struct rtattr
*flags_attr
,
1761 struct rtattr
*mask_attr
)
1763 SPRINT_BUF(namefrm
);
1770 done
= sprintf(out
, "0x%x", rta_getattr_be16(flags_attr
));
1772 sprintf(out
+ done
, "/%x", rta_getattr_be16(mask_attr
));
1774 print_string(PRINT_FP
, NULL
, "%s ", _SL_
);
1775 sprintf(namefrm
, "%s %%s", name
);
1776 print_string(PRINT_ANY
, name
, namefrm
, out
);
1779 static void flower_print_ct_state(struct rtattr
*flags_attr
,
1780 struct rtattr
*mask_attr
)
1784 uint16_t state_mask
;
1791 state
= rta_getattr_u16(flags_attr
);
1793 state_mask
= rta_getattr_u16(mask_attr
);
1795 state_mask
= UINT16_MAX
;
1797 for (i
= 0; i
< ARRAY_SIZE(flower_ct_states
); i
++) {
1798 if (!(state_mask
& flower_ct_states
[i
].flag
))
1801 if (state
& flower_ct_states
[i
].flag
)
1802 done
+= sprintf(out
+ done
, "+%s",
1803 flower_ct_states
[i
].str
);
1805 done
+= sprintf(out
+ done
, "-%s",
1806 flower_ct_states
[i
].str
);
1809 print_string(PRINT_ANY
, "ct_state", "\n ct_state %s", out
);
1812 static void flower_print_ct_label(struct rtattr
*attr
,
1813 struct rtattr
*mask_attr
)
1815 const unsigned char *str
;
1816 bool print_mask
= false;
1824 data_len
= RTA_PAYLOAD(attr
);
1825 hexstring_n2a(RTA_DATA(attr
), data_len
, out
, sizeof(out
));
1826 p
= out
+ data_len
*2;
1828 data_len
= RTA_PAYLOAD(attr
);
1829 str
= RTA_DATA(mask_attr
);
1832 for (i
= 0; !print_mask
&& i
< data_len
; i
++) {
1838 hexstring_n2a(RTA_DATA(mask_attr
), data_len
, p
,
1839 sizeof(out
)-(p
-out
));
1844 print_string(PRINT_ANY
, "ct_label", "\n ct_label %s", out
);
1847 static void flower_print_ct_zone(struct rtattr
*attr
,
1848 struct rtattr
*mask_attr
)
1850 print_masked_u16("ct_zone", attr
, mask_attr
);
1853 static void flower_print_ct_mark(struct rtattr
*attr
,
1854 struct rtattr
*mask_attr
)
1856 print_masked_u32("ct_mark", attr
, mask_attr
);
1859 static void flower_print_key_id(const char *name
, struct rtattr
*attr
)
1861 SPRINT_BUF(namefrm
);
1866 sprintf(namefrm
,"\n %s %%u", name
);
1867 print_uint(PRINT_ANY
, name
, namefrm
, rta_getattr_be32(attr
));
1870 static void flower_print_geneve_opts(const char *name
, struct rtattr
*attr
,
1873 struct rtattr
*tb
[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX
+ 1];
1874 int ii
, data_len
, offset
= 0, slen
= 0;
1875 struct rtattr
*i
= RTA_DATA(attr
);
1876 int rem
= RTA_PAYLOAD(attr
);
1877 __u8 type
, data_r
[rem
];
1878 char data
[rem
* 2 + 1];
1881 open_json_array(PRINT_JSON
, name
);
1883 parse_rtattr(tb
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX
, i
, rem
);
1884 class = rta_getattr_be16(tb
[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
]);
1885 type
= rta_getattr_u8(tb
[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
]);
1886 data_len
= RTA_PAYLOAD(tb
[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
]);
1887 hexstring_n2a(RTA_DATA(tb
[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
]),
1888 data_len
, data
, sizeof(data
));
1889 hex2mem(data
, data_r
, data_len
);
1890 offset
+= data_len
+ 20;
1891 rem
-= data_len
+ 20;
1892 i
= RTA_DATA(attr
) + offset
;
1894 open_json_object(NULL
);
1895 print_uint(PRINT_JSON
, "class", NULL
, class);
1896 print_uint(PRINT_JSON
, "type", NULL
, type
);
1897 open_json_array(PRINT_JSON
, "data");
1898 for (ii
= 0; ii
< data_len
; ii
++)
1899 print_uint(PRINT_JSON
, NULL
, NULL
, data_r
[ii
]);
1900 close_json_array(PRINT_JSON
, "data");
1901 close_json_object();
1903 slen
+= sprintf(strbuf
+ slen
, "%04x:%02x:%s",
1906 slen
+= sprintf(strbuf
+ slen
, ",");
1908 close_json_array(PRINT_JSON
, name
);
1911 static void flower_print_geneve_parts(const char *name
, struct rtattr
*attr
,
1912 char *key
, char *mask
)
1914 char *namefrm
= "\n geneve_opt %s";
1915 char *key_token
, *mask_token
, *out
;
1918 out
= malloc(RTA_PAYLOAD(attr
) * 4 + 3);
1923 key_token
= strsep(&key
, ",");
1924 mask_token
= strsep(&mask
, ",");
1926 len
+= sprintf(&out
[len
], "%s/%s,", key_token
, mask_token
);
1927 mask_token
= strsep(&mask
, ",");
1928 key_token
= strsep(&key
, ",");
1931 out
[len
- 1] = '\0';
1932 print_string(PRINT_FP
, name
, namefrm
, out
);
1936 static void flower_print_enc_opts(const char *name
, struct rtattr
*attr
,
1937 struct rtattr
*mask_attr
)
1939 struct rtattr
*key_tb
[TCA_FLOWER_KEY_ENC_OPTS_MAX
+ 1];
1940 struct rtattr
*msk_tb
[TCA_FLOWER_KEY_ENC_OPTS_MAX
+ 1];
1946 key
= malloc(RTA_PAYLOAD(attr
) * 2 + 1);
1950 msk
= malloc(RTA_PAYLOAD(attr
) * 2 + 1);
1954 parse_rtattr_nested(key_tb
, TCA_FLOWER_KEY_ENC_OPTS_MAX
, attr
);
1955 flower_print_geneve_opts("geneve_opt_key",
1956 key_tb
[TCA_FLOWER_KEY_ENC_OPTS_GENEVE
], key
);
1958 parse_rtattr_nested(msk_tb
, TCA_FLOWER_KEY_ENC_OPTS_MAX
, mask_attr
);
1959 flower_print_geneve_opts("geneve_opt_mask",
1960 msk_tb
[TCA_FLOWER_KEY_ENC_OPTS_GENEVE
], msk
);
1962 flower_print_geneve_parts(name
, attr
, key
, msk
);
1969 static void flower_print_masked_u8(const char *name
, struct rtattr
*attr
,
1970 struct rtattr
*mask_attr
,
1971 const char *(*value_to_str
)(__u8 value
))
1973 const char *value_str
= NULL
;
1975 SPRINT_BUF(namefrm
);
1982 value
= rta_getattr_u8(attr
);
1983 mask
= mask_attr
? rta_getattr_u8(mask_attr
) : UINT8_MAX
;
1984 if (mask
== UINT8_MAX
&& value_to_str
)
1985 value_str
= value_to_str(value
);
1988 done
= sprintf(out
, "%s", value_str
);
1990 done
= sprintf(out
, "%d", value
);
1992 if (mask
!= UINT8_MAX
)
1993 sprintf(out
+ done
, "/%d", mask
);
1995 sprintf(namefrm
,"\n %s %%s", name
);
1996 print_string(PRINT_ANY
, name
, namefrm
, out
);
1999 static void flower_print_u8(const char *name
, struct rtattr
*attr
)
2001 flower_print_masked_u8(name
, attr
, NULL
, NULL
);
2004 static void flower_print_u32(const char *name
, struct rtattr
*attr
)
2006 SPRINT_BUF(namefrm
);
2011 sprintf(namefrm
,"\n %s %%u", name
);
2012 print_uint(PRINT_ANY
, name
, namefrm
, rta_getattr_u32(attr
));
2015 static void flower_print_arp_op(const char *name
,
2016 struct rtattr
*op_attr
,
2017 struct rtattr
*mask_attr
)
2019 flower_print_masked_u8(name
, op_attr
, mask_attr
,
2020 flower_print_arp_op_to_name
);
2023 static int flower_print_opt(struct filter_util
*qu
, FILE *f
,
2024 struct rtattr
*opt
, __u32 handle
)
2026 struct rtattr
*tb
[TCA_FLOWER_MAX
+ 1];
2027 __be16 min_port_type
, max_port_type
;
2028 int nl_type
, nl_mask_type
;
2029 __be16 eth_type
= 0;
2030 __u8 ip_proto
= 0xff;
2035 parse_rtattr_nested(tb
, TCA_FLOWER_MAX
, opt
);
2038 print_uint(PRINT_ANY
, "handle", "handle 0x%x ", handle
);
2040 if (tb
[TCA_FLOWER_CLASSID
]) {
2041 __u32 h
= rta_getattr_u32(tb
[TCA_FLOWER_CLASSID
]);
2043 if (TC_H_MIN(h
) < TC_H_MIN_PRIORITY
||
2044 TC_H_MIN(h
) > (TC_H_MIN_PRIORITY
+ TC_QOPT_MAX_QUEUE
- 1)) {
2046 print_string(PRINT_ANY
, "classid", "classid %s ",
2047 sprint_tc_classid(h
, b1
));
2049 print_uint(PRINT_ANY
, "hw_tc", "hw_tc %u ",
2050 TC_H_MIN(h
) - TC_H_MIN_PRIORITY
);
2054 if (tb
[TCA_FLOWER_INDEV
]) {
2055 struct rtattr
*attr
= tb
[TCA_FLOWER_INDEV
];
2057 print_string(PRINT_ANY
, "indev", "\n indev %s",
2058 rta_getattr_str(attr
));
2061 open_json_object("keys");
2063 if (tb
[TCA_FLOWER_KEY_VLAN_ID
]) {
2064 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_VLAN_ID
];
2066 print_uint(PRINT_ANY
, "vlan_id", "\n vlan_id %u",
2067 rta_getattr_u16(attr
));
2070 if (tb
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
2071 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_VLAN_PRIO
];
2073 print_uint(PRINT_ANY
, "vlan_prio", "\n vlan_prio %d",
2074 rta_getattr_u8(attr
));
2077 if (tb
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]) {
2079 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
];
2081 print_string(PRINT_ANY
, "vlan_ethtype", "\n vlan_ethtype %s",
2082 ll_proto_n2a(rta_getattr_u16(attr
),
2086 if (tb
[TCA_FLOWER_KEY_CVLAN_ID
]) {
2087 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_CVLAN_ID
];
2089 print_uint(PRINT_ANY
, "cvlan_id", "\n cvlan_id %u",
2090 rta_getattr_u16(attr
));
2093 if (tb
[TCA_FLOWER_KEY_CVLAN_PRIO
]) {
2094 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_CVLAN_PRIO
];
2096 print_uint(PRINT_ANY
, "cvlan_prio", "\n cvlan_prio %d",
2097 rta_getattr_u8(attr
));
2100 if (tb
[TCA_FLOWER_KEY_CVLAN_ETH_TYPE
]) {
2102 struct rtattr
*attr
= tb
[TCA_FLOWER_KEY_CVLAN_ETH_TYPE
];
2104 print_string(PRINT_ANY
, "cvlan_ethtype", "\n cvlan_ethtype %s",
2105 ll_proto_n2a(rta_getattr_u16(attr
),
2109 flower_print_eth_addr("dst_mac", tb
[TCA_FLOWER_KEY_ETH_DST
],
2110 tb
[TCA_FLOWER_KEY_ETH_DST_MASK
]);
2111 flower_print_eth_addr("src_mac", tb
[TCA_FLOWER_KEY_ETH_SRC
],
2112 tb
[TCA_FLOWER_KEY_ETH_SRC_MASK
]);
2114 flower_print_eth_type(ð_type
, tb
[TCA_FLOWER_KEY_ETH_TYPE
]);
2115 flower_print_ip_proto(&ip_proto
, tb
[TCA_FLOWER_KEY_IP_PROTO
]);
2117 flower_print_ip_attr("ip_tos", tb
[TCA_FLOWER_KEY_IP_TOS
],
2118 tb
[TCA_FLOWER_KEY_IP_TOS_MASK
]);
2119 flower_print_ip_attr("ip_ttl", tb
[TCA_FLOWER_KEY_IP_TTL
],
2120 tb
[TCA_FLOWER_KEY_IP_TTL_MASK
]);
2122 flower_print_u32("mpls_label", tb
[TCA_FLOWER_KEY_MPLS_LABEL
]);
2123 flower_print_u8("mpls_tc", tb
[TCA_FLOWER_KEY_MPLS_TC
]);
2124 flower_print_u8("mpls_bos", tb
[TCA_FLOWER_KEY_MPLS_BOS
]);
2125 flower_print_u8("mpls_ttl", tb
[TCA_FLOWER_KEY_MPLS_TTL
]);
2127 flower_print_ip_addr("dst_ip", eth_type
,
2128 tb
[TCA_FLOWER_KEY_IPV4_DST
],
2129 tb
[TCA_FLOWER_KEY_IPV4_DST_MASK
],
2130 tb
[TCA_FLOWER_KEY_IPV6_DST
],
2131 tb
[TCA_FLOWER_KEY_IPV6_DST_MASK
]);
2133 flower_print_ip_addr("src_ip", eth_type
,
2134 tb
[TCA_FLOWER_KEY_IPV4_SRC
],
2135 tb
[TCA_FLOWER_KEY_IPV4_SRC_MASK
],
2136 tb
[TCA_FLOWER_KEY_IPV6_SRC
],
2137 tb
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]);
2139 nl_type
= flower_port_attr_type(ip_proto
, FLOWER_ENDPOINT_DST
);
2141 flower_print_port("dst_port", tb
[nl_type
]);
2142 nl_type
= flower_port_attr_type(ip_proto
, FLOWER_ENDPOINT_SRC
);
2144 flower_print_port("src_port", tb
[nl_type
]);
2146 if (!flower_port_range_attr_type(ip_proto
, FLOWER_ENDPOINT_DST
,
2147 &min_port_type
, &max_port_type
))
2148 flower_print_port_range("dst_port",
2149 tb
[min_port_type
], tb
[max_port_type
]);
2151 if (!flower_port_range_attr_type(ip_proto
, FLOWER_ENDPOINT_SRC
,
2152 &min_port_type
, &max_port_type
))
2153 flower_print_port_range("src_port",
2154 tb
[min_port_type
], tb
[max_port_type
]);
2156 flower_print_tcp_flags("tcp_flags", tb
[TCA_FLOWER_KEY_TCP_FLAGS
],
2157 tb
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]);
2159 nl_type
= flower_icmp_attr_type(eth_type
, ip_proto
,
2160 FLOWER_ICMP_FIELD_TYPE
);
2161 nl_mask_type
= flower_icmp_attr_mask_type(eth_type
, ip_proto
,
2162 FLOWER_ICMP_FIELD_TYPE
);
2163 if (nl_type
>= 0 && nl_mask_type
>= 0)
2164 flower_print_masked_u8("icmp_type", tb
[nl_type
],
2165 tb
[nl_mask_type
], NULL
);
2167 nl_type
= flower_icmp_attr_type(eth_type
, ip_proto
,
2168 FLOWER_ICMP_FIELD_CODE
);
2169 nl_mask_type
= flower_icmp_attr_mask_type(eth_type
, ip_proto
,
2170 FLOWER_ICMP_FIELD_CODE
);
2171 if (nl_type
>= 0 && nl_mask_type
>= 0)
2172 flower_print_masked_u8("icmp_code", tb
[nl_type
],
2173 tb
[nl_mask_type
], NULL
);
2175 flower_print_ip4_addr("arp_sip", tb
[TCA_FLOWER_KEY_ARP_SIP
],
2176 tb
[TCA_FLOWER_KEY_ARP_SIP_MASK
]);
2177 flower_print_ip4_addr("arp_tip", tb
[TCA_FLOWER_KEY_ARP_TIP
],
2178 tb
[TCA_FLOWER_KEY_ARP_TIP_MASK
]);
2179 flower_print_arp_op("arp_op", tb
[TCA_FLOWER_KEY_ARP_OP
],
2180 tb
[TCA_FLOWER_KEY_ARP_OP_MASK
]);
2181 flower_print_eth_addr("arp_sha", tb
[TCA_FLOWER_KEY_ARP_SHA
],
2182 tb
[TCA_FLOWER_KEY_ARP_SHA_MASK
]);
2183 flower_print_eth_addr("arp_tha", tb
[TCA_FLOWER_KEY_ARP_THA
],
2184 tb
[TCA_FLOWER_KEY_ARP_THA_MASK
]);
2186 flower_print_ip_addr("enc_dst_ip",
2187 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
] ?
2188 htons(ETH_P_IP
) : htons(ETH_P_IPV6
),
2189 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST
],
2190 tb
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
],
2191 tb
[TCA_FLOWER_KEY_ENC_IPV6_DST
],
2192 tb
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]);
2194 flower_print_ip_addr("enc_src_ip",
2195 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
] ?
2196 htons(ETH_P_IP
) : htons(ETH_P_IPV6
),
2197 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC
],
2198 tb
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
],
2199 tb
[TCA_FLOWER_KEY_ENC_IPV6_SRC
],
2200 tb
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]);
2202 flower_print_key_id("enc_key_id", tb
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
2204 flower_print_port("enc_dst_port", tb
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
2206 flower_print_ip_attr("enc_tos", tb
[TCA_FLOWER_KEY_ENC_IP_TOS
],
2207 tb
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]);
2208 flower_print_ip_attr("enc_ttl", tb
[TCA_FLOWER_KEY_ENC_IP_TTL
],
2209 tb
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]);
2210 flower_print_enc_opts("enc_opt", tb
[TCA_FLOWER_KEY_ENC_OPTS
],
2211 tb
[TCA_FLOWER_KEY_ENC_OPTS_MASK
]);
2213 flower_print_matching_flags("ip_flags", FLOWER_IP_FLAGS
,
2214 tb
[TCA_FLOWER_KEY_FLAGS
],
2215 tb
[TCA_FLOWER_KEY_FLAGS_MASK
]);
2217 flower_print_ct_state(tb
[TCA_FLOWER_KEY_CT_STATE
],
2218 tb
[TCA_FLOWER_KEY_CT_STATE_MASK
]);
2219 flower_print_ct_zone(tb
[TCA_FLOWER_KEY_CT_ZONE
],
2220 tb
[TCA_FLOWER_KEY_CT_ZONE_MASK
]);
2221 flower_print_ct_mark(tb
[TCA_FLOWER_KEY_CT_MARK
],
2222 tb
[TCA_FLOWER_KEY_CT_MARK_MASK
]);
2223 flower_print_ct_label(tb
[TCA_FLOWER_KEY_CT_LABELS
],
2224 tb
[TCA_FLOWER_KEY_CT_LABELS_MASK
]);
2226 close_json_object();
2228 if (tb
[TCA_FLOWER_FLAGS
]) {
2229 __u32 flags
= rta_getattr_u32(tb
[TCA_FLOWER_FLAGS
]);
2231 if (flags
& TCA_CLS_FLAGS_SKIP_HW
)
2232 print_bool(PRINT_ANY
, "skip_hw", "\n skip_hw", true);
2233 if (flags
& TCA_CLS_FLAGS_SKIP_SW
)
2234 print_bool(PRINT_ANY
, "skip_sw", "\n skip_sw", true);
2236 if (flags
& TCA_CLS_FLAGS_IN_HW
) {
2237 print_bool(PRINT_ANY
, "in_hw", "\n in_hw", true);
2239 if (tb
[TCA_FLOWER_IN_HW_COUNT
]) {
2240 __u32 count
= rta_getattr_u32(tb
[TCA_FLOWER_IN_HW_COUNT
]);
2242 print_uint(PRINT_ANY
, "in_hw_count",
2243 " in_hw_count %u", count
);
2246 else if (flags
& TCA_CLS_FLAGS_NOT_IN_HW
)
2247 print_bool(PRINT_ANY
, "not_in_hw", "\n not_in_hw", true);
2250 if (tb
[TCA_FLOWER_ACT
])
2251 tc_print_action(f
, tb
[TCA_FLOWER_ACT
], 0);
2256 struct filter_util flower_filter_util
= {
2258 .parse_fopt
= flower_parse_opt
,
2259 .print_fopt
= flower_print_opt
,