# Copyright 2018 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

# AF_NETLINK/NETLINK_ROUTE SCHED support.

include <linux/net.h>
include <linux/mpls.h>
include <uapi/linux/if.h>
include <uapi/linux/netlink.h>
include <uapi/linux/rtnetlink.h>
include <uapi/linux/netfilter.h>
include <uapi/linux/netfilter/x_tables.h>
include <uapi/linux/if_packet.h>
include <uapi/linux/can.h>
include <uapi/linux/pkt_cls.h>
include <uapi/linux/pkt_sched.h>
include <uapi/linux/tc_act/tc_bpf.h>
include <uapi/linux/tc_act/tc_ct.h>
include <uapi/linux/tc_act/tc_connmark.h>
include <uapi/linux/tc_act/tc_csum.h>
include <uapi/linux/tc_act/tc_ctinfo.h>
include <uapi/linux/tc_act/tc_defact.h>
include <uapi/linux/tc_act/tc_gact.h>
include <uapi/linux/tc_act/tc_ife.h>
include <uapi/linux/tc_act/tc_mirred.h>
include <uapi/linux/tc_act/tc_mpls.h>
include <uapi/linux/tc_act/tc_nat.h>
include <uapi/linux/tc_act/tc_pedit.h>
include <uapi/linux/tc_act/tc_sample.h>
include <uapi/linux/tc_act/tc_skbedit.h>
include <uapi/linux/tc_act/tc_skbmod.h>
include <uapi/linux/tc_act/tc_tunnel_key.h>
include <uapi/linux/tc_act/tc_vlan.h>
include <uapi/linux/tc_ematch/tc_em_cmp.h>
include <uapi/linux/tc_ematch/tc_em_ipt.h>
include <uapi/linux/tc_ematch/tc_em_meta.h>

sendmsg$nl_route_sched(fd sock_nl_route, msg ptr[in, msghdr_netlink[netlink_msg_route_sched]], f flags[send_flags])

netlink_msg_route_sched [
	newqdisc	netlink_msg[RTM_NEWQDISC, tcmsg[AF_UNSPEC], rtm_tca_policy]
	delqdisc	netlink_msg[RTM_DELQDISC, tcmsg[AF_UNSPEC], rtm_tca_policy]
	getqdisc	netlink_msg[RTM_GETQDISC, tcmsg[AF_UNSPEC], nlattr[TCA_DUMP_INVISIBLE, void]]
	newtclass	netlink_msg[RTM_NEWTCLASS, tcmsg[AF_UNSPEC], rtm_tca_policy$tclass]
	deltclass	netlink_msg[RTM_DELTCLASS, tcmsg[AF_UNSPEC], rtm_tca_policy$tclass]
	gettclass	netlink_msg[RTM_GETTCLASS, tcmsg[AF_UNSPEC], void]
	newtfilter	netlink_msg[RTM_NEWTFILTER, tcmsg[AF_UNSPEC], filter_policy]
	deltfilter	netlink_msg[RTM_DELTFILTER, tcmsg[AF_UNSPEC], filter_policy]
	gettfilter	netlink_msg[RTM_GETTFILTER, tcmsg[AF_UNSPEC], nlattr[TCA_CHAIN, int32]]
	newchain	netlink_msg[RTM_NEWCHAIN, tcmsg[AF_UNSPEC], filter_policy]
	delchain	netlink_msg[RTM_DELCHAIN, tcmsg[AF_UNSPEC], filter_policy]
	getchain	netlink_msg[RTM_GETCHAIN, tcmsg[AF_UNSPEC], nlattr[TCA_CHAIN, int32]]
	newtaction	netlink_msg[RTM_NEWACTION, tcamsg[AF_UNSPEC], nlattr[TCA_ACT_TAB, array[tca_actions]]]
	deltaction	netlink_msg[RTM_DELACTION, tcamsg[AF_UNSPEC], action_gd_policy]
	gettaction	netlink_msg[RTM_GETACTION, tcamsg[AF_UNSPEC], action_dump_policy]
] [varlen]

type tcmsg[FAMILY] {
	family		const[FAMILY, int8]
	tcm__pad1	const[0, int8]
	tcm__pad2	const[0, int16]
	ifindex		ifindex
	tcm_handle	tcm_handle
	tcm_parent	tcm_handle
	tcm_info	tcm_handle
}

tcm_handle {
	minor	flags[tcm_handle_offsets, int16]
	major	flags[tcm_handle_offsets, int16]
}

type tcamsg[FAMILY] {
	family		const[FAMILY, int8]
	tca__pad1	const[0, int8]
	tca__pad2	const[0, int16]
}

rtm_tca_policy [
	qdisc_kind_options	qdisc_kind_options
	TCA_RATE		nlattr[TCA_RATE, tc_estimator]
	TCA_STAB		nlnest[TCA_STAB, array[stab_policy]]
	TCA_INGRESS_BLOCK	nlattr[TCA_INGRESS_BLOCK, int32]
	TCA_EGRESS_BLOCK	nlattr[TCA_EGRESS_BLOCK, int32]
] [varlen]

rtm_tca_policy$tclass [
	tclass_kind_options	tclass_kind_options
	TCA_RATE		nlattr[TCA_RATE, tc_estimator]
] [varlen]

filter_policy [
	filter_kind_options	filter_kind_options
	TCA_RATE		nlattr[TCA_RATE, tc_estimator]
	TCA_CHAIN		nlattr[TCA_CHAIN, int32]
] [varlen]

type tca_kind_options_t[NAME, VALUES] {
	TCA_KIND	nlattr[TCA_KIND, string[NAME]]
	TCA_OPTIONS	nlattr[TCA_OPTIONS, VALUES]
}
# ------------------------------ tc qdisc ------------------------------
qdisc_kind_options [
	q_cake			tca_kind_options_t["cake", array[cake_policy]]
	q_cbq			tca_kind_options_t["cbq", array[cbs_policy]]
	q_cbs			tca_kind_options_t["cbs", cbs_policy]
	q_choke			tca_kind_options_t["choke", array[choke_policy]]
	q_codel			tca_kind_options_t["codel", array[codel_policy]]
	q_etf			tca_kind_options_t["etf", etf_policy]
	q_bfifo			tca_kind_options_t["bfifo", int32]
	q_pfifo			tca_kind_options_t["pfifo", int32]
	q_pfifo_head_drop	tca_kind_options_t["pfifo_head_drop", int32]
	q_fq			tca_kind_options_t["fq", array[fq_policy]]
	q_fq_codel		tca_kind_options_t["fq_codel", array[fq_codel_policy]]
	q_fq_pie		tca_kind_options_t["fq_pie", array[fq_pie_policy]]
	q_gred			tca_kind_options_t["gred", array[gred_policy]]
	q_hfsc			tca_kind_options_t["hfsc", hfsc_policy]
	q_hhf			tca_kind_options_t["hhf", array[hhf_policy]]
	q_htb			tca_kind_options_t["htb", array[htb_policy]]
	q_mqprio		tca_kind_options_t["mqprio", tc_mqprio_message]
	q_multiq		tca_kind_options_t["multiq", tc_multiq_qopt]
	q_netem			tca_kind_options_t["netem", tc_netem_message]
	q_pie			tca_kind_options_t["pie", array[pie_policy]]
	q_prio			tca_kind_options_t["prio", tc_prio_qopt]
	q_plug			tca_kind_options_t["plug", tc_plug_qopt]
	q_red			tca_kind_options_t["red", array[red_policy]]
	q_rr			tca_kind_options_t["rr", tc_prio_qopt]
	q_sfb			tca_kind_options_t["sfb", sfb_policy]
	q_sfq			tca_kind_options_t["sfq", tc_sfq_qopt_v1]
	q_skbprio		tca_kind_options_t["skbprio", int32]
	q_taprio		tca_kind_options_t["taprio", array[taprio_policy]]
	q_tbf			tca_kind_options_t["tbf", array[tbf_policy]]
	q_atm			nlattr[TCA_KIND, string["atm"]]
	q_drr			nlattr[TCA_KIND, string["drr"]]
	q_blackhole		nlattr[TCA_KIND, string["blackhole"]]
	q_clsact		nlattr[TCA_KIND, string["clsact"]]
	q_pfifo_fast		nlattr[TCA_KIND, string["pfifo_fast"]]
	q_qfg			nlattr[TCA_KIND, string["qfq"]]
	q_ingress		nlattr[TCA_KIND, string["ingress"]]
	q_mq			nlattr[TCA_KIND, string["mq"]]
] [varlen]

cake_policy [
	TCA_CAKE_BASE_RATE64	nlattr[TCA_CAKE_BASE_RATE64, int64]
	TCA_CAKE_DIFFSERV_MODE	nlattr[TCA_CAKE_DIFFSERV_MODE, flags[tc_cake_diffserv_mode, int32]]
	TCA_CAKE_ATM		nlattr[TCA_CAKE_ATM, flags[tc_cake_atm, int32]]
	TCA_CAKE_FLOW_MODE	nlattr[TCA_CAKE_FLOW_MODE, flags[tc_cake_flow_mode, int32]]
	TCA_CAKE_OVERHEAD	nlattr[TCA_CAKE_OVERHEAD, int32[-64:256]]
	TCA_CAKE_RTT		nlattr[TCA_CAKE_RTT, int32]
	TCA_CAKE_TARGET		nlattr[TCA_CAKE_TARGET, int32]
	TCA_CAKE_AUTORATE	nlattr[TCA_CAKE_AUTORATE, int32]
	TCA_CAKE_MEMORY		nlattr[TCA_CAKE_MEMORY, int32]
	TCA_CAKE_NAT		nlattr[TCA_CAKE_NAT, int32[0:1]]
	TCA_CAKE_RAW		nlattr[TCA_CAKE_RAW, int32[0:1]]
	TCA_CAKE_WASH		nlattr[TCA_CAKE_WASH, int32[0:1]]
	TCA_CAKE_MPU		nlattr[TCA_CAKE_MPU, int32[0:256]]
	TCA_CAKE_INGRESS	nlattr[TCA_CAKE_INGRESS, int32[0:1]]
	TCA_CAKE_ACK_FILTER	nlattr[TCA_CAKE_ACK_FILTER, flags[tc_cake_ack_filter, int32]]
	TCA_CAKE_SPLIT_GSO	nlattr[TCA_CAKE_SPLIT_GSO, int32[0:1]]
	TCA_CAKE_FWMARK		nlattr[TCA_CAKE_FWMARK, int32]
] [varlen]

cbs_policy [
	TCA_CBS_PARMS	nlattr[TCA_CBS_PARMS, tc_cbs_qopt]
] [varlen]

choke_policy [
	TCA_CHOKE_PARMS	nlattr[TCA_CHOKE_PARMS, tc_red_qopt]
	TCA_CHOKE_STAB	nlattr[TCA_CHOKE_STAB, array[int8, 256]]
	TCA_CHOKE_MAX_P	nlattr[TCA_CHOKE_MAX_P, int32]
] [varlen]

codel_policy [
	TCA_CODEL_TARGET	nlattr[TCA_CODEL_TARGET, int32]
	TCA_CODEL_LIMIT		nlattr[TCA_CODEL_LIMIT, int32]
	TCA_CODEL_INTERVAL	nlattr[TCA_CODEL_INTERVAL, int32]
	TCA_CODEL_ECN		nlattr[TCA_CODEL_ECN, int32[0:1]]
	TCA_CODEL_CE_THRESHOLD	nlattr[TCA_CODEL_CE_THRESHOLD, int32]
] [varlen]

etf_policy [
	TCA_ETF_PARMS	nlattr[TCA_ETF_PARMS, tc_etf_qopt]
] [varlen]

tc_etf_qopt {
	delta	int32
	clockid	flags[tc_etf_clock_id, int32]
	flags	flags[tc_etf_flags, int32]
}

fq_policy [
	TCA_FQ_PLIMIT			nlattr[TCA_FQ_PLIMIT, int32]
	TCA_FQ_FLOW_PLIMIT		nlattr[TCA_FQ_FLOW_PLIMIT, int32]
	TCA_FQ_QUANTUM			nlattr[TCA_FQ_QUANTUM, int32]
	TCA_FQ_INITIAL_QUANTUM		nlattr[TCA_FQ_INITIAL_QUANTUM, int32]
	TCA_FQ_RATE_ENABLE		nlattr[TCA_FQ_RATE_ENABLE, int32[0:1]]
	TCA_FQ_FLOW_DEFAULT_RATE	nlattr[TCA_FQ_FLOW_DEFAULT_RATE, int32]
	TCA_FQ_FLOW_MAX_RATE		nlattr[TCA_FQ_FLOW_MAX_RATE, int32]
	TCA_FQ_BUCKETS_LOG		nlattr[TCA_FQ_BUCKETS_LOG, int32[0:32]]
	TCA_FQ_FLOW_REFILL_DELAY	nlattr[TCA_FQ_FLOW_REFILL_DELAY, int32]
	TCA_FQ_ORPHAN_MASK		nlattr[TCA_FQ_ORPHAN_MASK, int32]
	TCA_FQ_LOW_RATE_THRESHOLD	nlattr[TCA_FQ_LOW_RATE_THRESHOLD, int32]
	TCA_FQ_CE_THRESHOLD		nlattr[TCA_FQ_CE_THRESHOLD, int32]
	TCA_FQ_TIMER_SLACK		nlattr[TCA_FQ_TIMER_SLACK, int32]
] [varlen]

fq_codel_policy [
	TCA_FQ_CODEL_TARGET			nlattr[TCA_FQ_CODEL_TARGET, int32]
	TCA_FQ_CODEL_LIMIT			nlattr[TCA_FQ_CODEL_LIMIT, int32]
	TCA_FQ_CODEL_INTERVAL			nlattr[TCA_FQ_CODEL_INTERVAL, int32]
	TCA_FQ_CODEL_ECN			nlattr[TCA_FQ_CODEL_ECN, int32[0:1]]
	TCA_FQ_CODEL_FLOWS			nlattr[TCA_FQ_CODEL_FLOWS, int32]
	TCA_FQ_CODEL_QUANTUM			nlattr[TCA_FQ_CODEL_QUANTUM, int32]
	TCA_FQ_CODEL_CE_THRESHOLD		nlattr[TCA_FQ_CODEL_CE_THRESHOLD, int32]
	TCA_FQ_CODEL_DROP_BATCH_SIZE		nlattr[TCA_FQ_CODEL_DROP_BATCH_SIZE, int32]
	TCA_FQ_CODEL_MEMORY_LIMIT		nlattr[TCA_FQ_CODEL_MEMORY_LIMIT, int32]
	TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR	nlattr[TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR, int8]
	TCA_FQ_CODEL_CE_THRESHOLD_MASK		nlattr[TCA_FQ_CODEL_CE_THRESHOLD_MASK, int8]
] [varlen]

fq_pie_policy [
	TCA_FQ_PIE_LIMIT		nlattr[TCA_FQ_PIE_LIMIT, int32]
	TCA_FQ_PIE_FLOWS		nlattr[TCA_FQ_PIE_FLOWS, int32[1:65535]]
	TCA_FQ_PIE_TARGET		nlattr[TCA_FQ_PIE_TARGET, int32]
	TCA_FQ_PIE_TUPDATE		nlattr[TCA_FQ_PIE_TUPDATE, int32]
	TCA_FQ_PIE_ALPHA		nlattr[TCA_FQ_PIE_ALPHA, int32[0:32]]
	TCA_FQ_PIE_BETA			nlattr[TCA_FQ_PIE_BETA, int32[0:32]]
	TCA_FQ_PIE_QUANTUM		nlattr[TCA_FQ_PIE_QUANTUM, int32]
	TCA_FQ_PIE_MEMORY_LIMIT		nlattr[TCA_FQ_PIE_MEMORY_LIMIT, int32]
	TCA_FQ_PIE_ECN_PROB		nlattr[TCA_FQ_PIE_ECN_PROB, int32[0:100]]
	TCA_FQ_PIE_ECN			nlattr[TCA_FQ_PIE_ECN, bool32]
	TCA_FQ_PIE_BYTEMODE		nlattr[TCA_FQ_PIE_BYTEMODE, bool32]
	TCA_FQ_PIE_DQ_RATE_ESTIMATOR	nlattr[TCA_FQ_PIE_DQ_RATE_ESTIMATOR, bool32]
] [varlen]

# TODO: we should not have TCA_GRED_PARMS and TCA_GRED_STAB when do init
gred_policy [
	TCA_GRED_PARMS	nlattr[TCA_GRED_PARMS, tc_gred_qopt]
	TCA_GRED_STAB	nlattr[TCA_GRED_STAB, array[int8, 256]]
	TCA_GRED_DPS	nlattr[TCA_GRED_DPS, tc_gred_sopt]
	TCA_GRED_MAX_P	nlattr[TCA_GRED_MAX_P, int32]
	TCA_GRED_LIMIT	nlattr[TCA_GRED_LIMIT, int32]
] [varlen]

hfsc_policy [
	TCA_HFSC_RSC	nlattr[TCA_HFSC_RSC, tc_service_curve]
	TCA_HFSC_FSC	nlattr[TCA_HFSC_FSC, tc_service_curve]
	TCA_HFSC_USC	nlattr[TCA_HFSC_USC, tc_service_curve]
] [varlen]

tc_service_curve {
	m1	int32
	d	int32
	m2	int32
}

hhf_policy [
	TCA_HHF_BACKLOG_LIMIT	nlattr[TCA_HHF_BACKLOG_LIMIT, int32]
	TCA_HHF_QUANTUM		nlattr[TCA_HHF_QUANTUM, int32]
	TCA_HHF_HH_FLOWS_LIMIT	nlattr[TCA_HHF_HH_FLOWS_LIMIT, int32]
	TCA_HHF_RESET_TIMEOUT	nlattr[TCA_HHF_RESET_TIMEOUT, int32]
	TCA_HHF_ADMIT_BYTES	nlattr[TCA_HHF_ADMIT_BYTES, int32]
	TCA_HHF_EVICT_TIMEOUT	nlattr[TCA_HHF_EVICT_TIMEOUT, int32]
	TCA_HHF_NON_HH_WEIGHT	nlattr[TCA_HHF_NON_HH_WEIGHT, int32]
] [varlen]

htb_policy [
	TCA_HTB_INIT		nlattr[TCA_HTB_INIT, tc_htb_glob]
	TCA_HTB_DIRECT_QLEN	nlattr[TCA_HTB_DIRECT_QLEN, int32]
] [varlen]

tc_mqprio_message {
	qopt	tc_mqprio_qopt
	attrs	array[mqprio_policy]
}

mqprio_policy [
	TCA_MQPRIO_MODE		nlattr[TCA_MQPRIO_MODE, flags[tc_mqprio_modes, int16]]
	TCA_MQPRIO_SHAPER	nlattr[TCA_MQPRIO_SHAPER, flags[tc_mqprio_shapers, int16]]
	TCA_MQPRIO_MIN_RATE64	nlnest[TCA_MQPRIO_MIN_RATE64, array[nlattr[TCA_MQPRIO_MIN_RATE64, int64], 0:16]]
	TCA_MQPRIO_MAX_RATE64	nlnest[TCA_MQPRIO_MAX_RATE64, array[nlattr[TCA_MQPRIO_MAX_RATE64, int64], 0:16]]
] [varlen]

tc_netem_message {
	qopt	tc_netem_qopt
	attrs	array[netem_policy]
}

netem_policy [
	TCA_NETEM_CORR		nlattr[TCA_NETEM_CORR, tc_netem_corr]
	TCA_NETEM_DELAY_DIST	nlattr[TCA_NETEM_DELAY_DIST, array[int8, 0:100]]
	TCA_NETEM_REORDER	nlattr[TCA_NETEM_REORDER, tc_netem_reorder]
	TCA_NETEM_CORRUPT	nlattr[TCA_NETEM_CORRUPT, tc_netem_corrupt]
	TCA_NETEM_LOSS		nlnest[TCA_NETEM_LOSS, array[netem_loss_policy]]
	TCA_NETEM_RATE		nlattr[TCA_NETEM_RATE, tc_netem_rate]
	TCA_NETEM_ECN		nlattr[TCA_NETEM_ECN, int32[0:1]]
	TCA_NETEM_RATE64	nlattr[TCA_NETEM_RATE64, int64[0x100000000:0xffffffffffffffff]]
	TCA_NETEM_LATENCY64	nlattr[TCA_NETEM_LATENCY64, int64]
	TCA_NETEM_JITTER64	nlattr[TCA_NETEM_JITTER64, int64]
	TCA_NETEM_SLOT		nlattr[TCA_NETEM_SLOT, tc_netem_slot]
] [varlen]

netem_loss_policy [
	NETEM_LOSS_GI	nlattr[NETEM_LOSS_GI, tc_netem_gimodel]
	NETEM_LOSS_GE	nlattr[NETEM_LOSS_GE, tc_netem_gemodel]
] [varlen]

pie_policy [
	TCA_PIE_TARGET		nlattr[TCA_PIE_TARGET, int32]
	TCA_PIE_LIMIT		nlattr[TCA_PIE_LIMIT, int32]
	TCA_PIE_TUPDATE		nlattr[TCA_PIE_TUPDATE, int32]
	TCA_PIE_ALPHA		nlattr[TCA_PIE_ALPHA, int32[0:32]]
	TCA_PIE_BETA		nlattr[TCA_PIE_BETA, int32[0:32]]
	TCA_PIE_ECN		nlattr[TCA_PIE_ECN, int32[0:1]]
	TCA_PIE_BYTEMODE	nlattr[TCA_PIE_BYTEMODE, int32[0:1]]
] [varlen]

red_policy [
	TCA_RED_PARMS			nlattr[TCA_RED_PARMS, tc_red_qopt]
	TCA_RED_STAB			nlattr[TCA_RED_STAB, array[int8, 256]]
	TCA_RED_MAX_P			nlattr[TCA_RED_MAX_P, int32]
	TCA_RED_FLAGS			nlattr[TCA_RED_FLAGS, nla_bitfield32[red_supported_flags]]
	TCA_RED_EARLY_DROP_BLOCK	nlattr[TCA_RED_EARLY_DROP_BLOCK, int32]
	TCA_RED_MARK_BLOCK		nlattr[TCA_RED_MARK_BLOCK, int32]
] [varlen]

red_supported_flags = TC_RED_HISTORIC_FLAGS, TC_RED_NODROP

sfb_policy [
	TCA_SFB_PARMS	nlattr[TCA_SFB_PARMS, tc_sfb_qopt]
] [varlen]

entry_policy$taprio [
	TCA_TAPRIO_SCHED_ENTRY_CMD		nlattr[TCA_TAPRIO_SCHED_ENTRY_CMD, int8]
	TCA_TAPRIO_SCHED_ENTRY_GATE_MASK	nlattr[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, int32]
	TCA_TAPRIO_SCHED_ENTRY_INTERVAL		nlattr[TCA_TAPRIO_SCHED_ENTRY_INTERVAL, int32]
] [varlen]

taprio_policy [
	TCA_TAPRIO_ATTR_PRIOMAP				nlattr[TCA_TAPRIO_ATTR_PRIOMAP, tc_mqprio_qopt]
	TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST		nlnest[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST, array[nlnest[TCA_TAPRIO_SCHED_ENTRY, array[entry_policy$taprio]]]]
	TCA_TAPRIO_ATTR_SCHED_BASE_TIME			nlattr[TCA_TAPRIO_ATTR_SCHED_BASE_TIME, int64]
	TCA_TAPRIO_ATTR_SCHED_CLOCKID			nlattr[TCA_TAPRIO_ATTR_SCHED_CLOCKID, int32]
	TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME		nlattr[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME, int64]
	TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME_EXTENSION	nlattr[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME_EXTENSION, int64]
	TCA_TAPRIO_ATTR_FLAGS				nlattr[TCA_TAPRIO_ATTR_FLAGS, int32]
	TCA_TAPRIO_ATTR_TXTIME_DELAY			nlattr[TCA_TAPRIO_ATTR_TXTIME_DELAY, int32]
] [varlen]

tbf_policy [
	TCA_TBF_PARMS	nlattr[TCA_TBF_PARMS, tc_tbf_qopt]
	TCA_TBF_RTAB	nlattr[TCA_TBF_RTAB, array[int32, 256]]
	TCA_TBF_PTAB	nlattr[TCA_TBF_PTAB, array[int32, 256]]
	TCA_TBF_RATE64	nlattr[TCA_TBF_RATE64, int64[0x100000000:0xffffffffffffffff]]
	TCA_TBF_PRATE64	nlattr[TCA_TBF_PRATE64, int64[0x100000000:0xffffffffffffffff]]
	TCA_TBF_BURST	nlattr[TCA_TBF_BURST, int32]
	TCA_TBF_PBURST	nlattr[TCA_TBF_PBURST, int32[0:9000]]
] [varlen]

tc_cbs_qopt {
	offload		int8
	_pad		array[const[0, int8], 3]
	hicredit	int32
	locredit	int32
	idleslope	int32
	sendslope	int32
}

# NEED: limit >= qth_max >= qth_min
tc_red_qopt {
	limit		int32
	qth_min		int32
	qth_max		int32
	Wlog		int8[0:32]
	Plog		int8[0:32]
	Scell_log	int8[0:32]
	flag		int8[0:8]
}

tc_gred_sopt {
	DPs	int32[0:16]
	def_DP	int32[0:16]
	grio	int8[0:1]
	flags	int8[0:8]
	pad1	const[0, int16]
}

tc_gred_qopt {
	limit		int32
	qth_min		int32
	qth_max		int32
	DP		int32[0:16]
	backlog		int32
	qave		int32
	forced		int32
	early		int32
	other		int32
	pdrop		int32
	Wlog		int8[0:32]
	Plog		int8[0:32]
	Scell_log	int8[0:32]
	prio		int8
	packets		int32
	bytesin		int32
}

tc_htb_glob {
	version		const[3, int32]
	rate2quantum	int32
	defcls		int32
	debug		const[0, int32]
	direct_pkts	const[0, int32]
}

tc_mqprio_qopt {
	num_tc		int8[0:TC_MAX_QUEUE]
	prio_tc_map	array[int8[0:TC_MAX_QUEUE], 16]
	hw		int8[0:TC_MQPRIO_HW_OFFLOAD_MAX]
	count		array[int16, TC_QOPT_MAX_QUEUE]
	offset		array[int16, TC_QOPT_MAX_QUEUE]
}

define TC_MAX_QUEUE	16

tc_multiq_qopt {
	bands		int16
	max_bands	int16
}

tc_netem_qopt {
	latency		int32
	limit		int32
	loss		int32
	gap		int32
	duplicate	int32
	jitter		int32
}

tc_netem_corr {
	delay_corr	int32
	loss_corr	int32
	dup_corr	int32
}

tc_netem_reorder {
	probability	int32
	correlation	int32
}

tc_netem_corrupt {
	probability	int32
	correlation	int32
}

tc_netem_rate {
	rate		int32
	packet_overhead	int32
	cell_size	int32
	cell_overhead	int32
}

tc_netem_slot {
	min_delay	int64
	max_delay	int64
	max_packets	int32
	max_bytes	int32
	dist_delay	int64
	dist_jitter	int64
}

tc_netem_gimodel {
	p13	int32
	p31	int32
	p32	int32
	p14	int32
	p23	int32
}

tc_netem_gemodel {
	p	int32
	r	int32
	h	int32
	k1	int32
}

tc_prio_qopt {
	bands	int32
	priomap	array[int8, TC_PRIO_MAX1]
}

define TC_PRIO_MAX1	TC_PRIO_MAX + 1

tc_plug_qopt {
	action	flags[tc_plug_actions, int32]
	limit	int32
}

tc_sfb_qopt {
	rehash_interval	int32
	warmup_time	int32
	max		int32
	bin_size	int32
	increment	int32
	decrement	int32
	limit		int32
	penalty_rate	int32
	penalty_burst	int32
}

tc_sfq_qopt_v1 {
	v0		tc_sfq_qopt
	depth		int32
	headdrop	int32[0:1]
	limit		int32
	qth_min		int32
	qth_max		int32
	Wlog		int8[0:32]
	Plog		int8[0:32]
	Scell_log	int8[0:32]
	flag		int8[0:8]
	max_P		int32
	stats		tc_sfqred_stats
}

tc_sfq_qopt {
	quantum		int32
	perturb_period	int32
	limit		int32
	divisor		int32
	flows		int32
}

tc_sfqred_stats {
	prob_drop		int32
	forced_drop		int32
	prob_mark		int32
	forced_mark		int32
	prob_mark_head		int32
	forced_mark_head	int32
}

tc_tbf_qopt {
	rate		tc_ratespec
	peakrate	tc_ratespec
	limit		int32
	buffer		int32
	mtu		int32[0:9000]
}

# ------------------------------ tc class ------------------------------
tclass_kind_options [
	c_drr		tca_kind_options_t["drr", drr_policy]
	c_hfsc		tca_kind_options_t["hfsc", array[hfsc_policy]]
	c_htb		tca_kind_options_t["htb", array[htb_policy$class]]
	c_qfq		tca_kind_options_t["qfq", array[qfq_policy]]
	c_cake		nlattr[TCA_KIND, string["cake"]]
	c_cbs		nlattr[TCA_KIND, string["cbs"]]
	c_fq_codel	nlattr[TCA_KIND, string["fq_codel"]]
	c_mq		nlattr[TCA_KIND, string["mq"]]
	c_mqprio	nlattr[TCA_KIND, string["mqprio"]]
	c_multiq	nlattr[TCA_KIND, string["multiq"]]
	c_netem		nlattr[TCA_KIND, string["netem"]]
	c_prio		nlattr[TCA_KIND, string["prio"]]
	c_red		nlattr[TCA_KIND, string["red"]]
	c_sfb		nlattr[TCA_KIND, string["sfb"]]
	c_sfq		nlattr[TCA_KIND, string["sfq"]]
	c_skbprio	nlattr[TCA_KIND, string["skbprio"]]
	c_taprio	nlattr[TCA_KIND, string["taprio"]]
	c_tbf		nlattr[TCA_KIND, string["tbf"]]
	c_ingress	nlattr[TCA_KIND, string["ingress"]]
	c_clsact	nlattr[TCA_KIND, string["clsact"]]
] [varlen]

drr_policy [
	TCA_DRR_QUANTUM	nlattr[TCA_DRR_QUANTUM, int32]
] [varlen]

htb_policy$class [
	TCA_HTB_PARMS	nlattr[TCA_HTB_PARMS, tc_htb_opt]
	TCA_HTB_CTAB	nlattr[TCA_HTB_CTAB, array[int32, 256]]
	TCA_HTB_RTAB	nlattr[TCA_HTB_RTAB, array[int32, 256]]
	TCA_HTB_RATE64	nlattr[TCA_HTB_RATE64, int64]
	TCA_HTB_CEIL64	nlattr[TCA_HTB_CEIL64, int64]
	TCA_HTB_OFFLOAD	nlattr[TCA_HTB_OFFLOAD, void]
] [varlen]

qfq_policy [
	TCA_QFQ_WEIGHT	nlattr[TCA_QFQ_WEIGHT, int32]
	TCA_QFQ_LMAX	nlattr[TCA_QFQ_LMAX, int32]
] [varlen]

tc_htb_opt {
	rate	tc_ratespec
	ceil	tc_ratespec
	buffer	int32
	cbuffer	int32
	quantum	int32
	level	int32
	prio	int32
}

# ------------------------------ tc filter ------------------------------

filter_kind_options [
	f_basic		tca_kind_options_t["basic", array[basic_policy]]
	f_bpf		tca_kind_options_t["bpf", array[bpf_policy]]
	f_cgroup	tca_kind_options_t["cgroup", array[cgroup_policy]]
	f_flow		tca_kind_options_t["flow", array[flow_policy]]
	f_flower	tca_kind_options_t["flower", array[fl_policy]]
	f_fw		tca_kind_options_t["fw", array[fw_policy]]
	f_matchall	tca_kind_options_t["matchall", array[mall_policy]]
	f_route		tca_kind_options_t["route", array[route4_policy]]
	f_u32		tca_kind_options_t["u32", array[u32_policy]]
] [varlen]

basic_policy [
	TCA_BASIC_CLASSID	nlattr[TCA_BASIC_CLASSID, tcm_handle]
	TCA_BASIC_EMATCHES	nlnest[TCA_BASIC_EMATCHES, array[em_policy]]
	TCA_BASIC_ACT		nlattr[TCA_BASIC_ACT, array[tca_actions]]
	TCA_BASIC_POLICE	nlattr[TCA_BASIC_POLICE, array[police_policy]]
] [varlen]

bpf_policy [
	TCA_BPF_ACT		nlattr[TCA_BPF_ACT, array[tca_actions]]
	TCA_BPF_POLICE		nlattr[TCA_BPF_POLICE, array[police_policy]]
	TCA_BPF_CLASSID		nlattr[TCA_BPF_CLASSID, tcm_handle]
	TCA_BPF_OPS		bpf_policy$ops
	TCA_BPF_FD		nlattr[TCA_BPF_FD, fd_bpf_prog]
	TCA_BPF_NAME		nlattr[TCA_BPF_NAME, string[filename]]
	TCA_BPF_FLAGS		nlattr[TCA_BPF_FLAGS, int32[0:1]]
	TCA_BPF_FLAGS_GEN	nlattr[TCA_BPF_FLAGS_GEN, int32[0:8]]
] [varlen]

bpf_policy$ops {
	TCA_BPF_OPS_LEN	nlattr[TCA_BPF_OPS_LEN, len[bpf_policy$ops:TCA_BPF_OPS:payload, int16]]
	TCA_BPF_OPS	nlattr[TCA_BPF_OPS, array[sock_filter]]
} [packed]

cgroup_policy [
	TCA_CGROUP_ACT		nlattr[TCA_CGROUP_ACT, array[tca_actions]]
	TCA_CGROUP_POLICE	nlattr[TCA_CGROUP_POLICE, array[police_policy]]
	TCA_CGROUP_EMATCHES	nlnest[TCA_CGROUP_EMATCHES, array[em_policy]]
] [varlen]

flow_policy [
	TCA_FLOW_KEYS		nlattr[TCA_FLOW_KEYS, int32[0:0x1ffff]]
	TCA_FLOW_MODE		nlattr[TCA_FLOW_MODE, flags[tc_flow_modes, int32]]
	TCA_FLOW_BASECLASS	nlattr[TCA_FLOW_BASECLASS, tcm_handle]
	TCA_FLOW_RSHIFT		nlattr[TCA_FLOW_RSHIFT, int32]
	TCA_FLOW_ADDEND		nlattr[TCA_FLOW_ADDEND, int32]
	TCA_FLOW_MASK		nlattr[TCA_FLOW_MASK, int32]
	TCA_FLOW_XOR		nlattr[TCA_FLOW_XOR, int32]
	TCA_FLOW_DIVISOR	nlattr[TCA_FLOW_DIVISOR, int32]
	TCA_FLOW_ACT		nlnest[TCA_FLOW_ACT, array[tca_actions]]
	TCA_FLOW_POLICE		nlnest[TCA_FLOW_POLICE, array[police_policy]]
	TCA_FLOW_EMATCHES	nlnest[TCA_FLOW_EMATCHES, array[em_policy]]
	TCA_FLOW_PERTURB	nlattr[TCA_FLOW_PERTURB, int32]
] [varlen]

fl_policy [
	TCA_FLOWER_CLASSID			nlattr[TCA_FLOWER_CLASSID, tcm_handle]
	TCA_FLOWER_INDEV			nlattr[TCA_FLOWER_INDEV, devname]
	TCA_FLOWER_ACT				nlattr[TCA_FLOWER_ACT, array[tca_actions]]
	TCA_FLOWER_KEY_ETH_DST			nlattr[TCA_FLOWER_KEY_ETH_DST, mac_addr]
	TCA_FLOWER_KEY_ETH_DST_MASK		nlattr[TCA_FLOWER_KEY_ETH_DST_MASK, mac_addr_mask]
	TCA_FLOWER_KEY_ETH_SRC			nlattr[TCA_FLOWER_KEY_ETH_SRC, mac_addr]
	TCA_FLOWER_KEY_ETH_SRC_MASK		nlattr[TCA_FLOWER_KEY_ETH_SRC_MASK, mac_addr_mask]
	TCA_FLOWER_KEY_ETH_TYPE			nlattr[TCA_FLOWER_KEY_ETH_TYPE, flags[ether_types, int16be]]
	TCA_FLOWER_KEY_IP_PROTO			nlattr[TCA_FLOWER_KEY_IP_PROTO, flags[ipv6_types, int8]]
	TCA_FLOWER_KEY_IPV4_SRC			nlattr[TCA_FLOWER_KEY_IPV4_SRC, ipv4_addr]
	TCA_FLOWER_KEY_IPV4_SRC_MASK		nlattr[TCA_FLOWER_KEY_IPV4_SRC_MASK, ipv4_addr_mask]
	TCA_FLOWER_KEY_IPV4_DST			nlattr[TCA_FLOWER_KEY_IPV4_DST, ipv4_addr]
	TCA_FLOWER_KEY_IPV4_DST_MASK		nlattr[TCA_FLOWER_KEY_IPV4_DST_MASK, ipv4_addr_mask]
	TCA_FLOWER_KEY_IPV6_SRC			nlattr[TCA_FLOWER_KEY_IPV6_SRC, ipv6_addr]
	TCA_FLOWER_KEY_IPV6_SRC_MASK		nlattr[TCA_FLOWER_KEY_IPV6_SRC_MASK, ipv6_addr_mask]
	TCA_FLOWER_KEY_IPV6_DST			nlattr[TCA_FLOWER_KEY_IPV6_DST, ipv6_addr]
	TCA_FLOWER_KEY_IPV6_DST_MASK		nlattr[TCA_FLOWER_KEY_IPV6_DST_MASK, ipv6_addr_mask]
	TCA_FLOWER_KEY_TCP_SRC			nlattr[TCA_FLOWER_KEY_TCP_SRC, int16[0:0]]
	TCA_FLOWER_KEY_TCP_DST			nlattr[TCA_FLOWER_KEY_TCP_DST, int16[0:0]]
	TCA_FLOWER_KEY_UDP_SRC			nlattr[TCA_FLOWER_KEY_UDP_SRC, int16[0:0]]
	TCA_FLOWER_KEY_UDP_DST			nlattr[TCA_FLOWER_KEY_UDP_DST, int16[0:0]]
	TCA_FLOWER_FLAGS			nlattr[TCA_FLOWER_FLAGS, flags[tc_flower_flags, int32]]
	TCA_FLOWER_KEY_VLAN_ID			nlattr[TCA_FLOWER_KEY_VLAN_ID, int16[0:4095]]
	TCA_FLOWER_KEY_VLAN_PRIO		nlattr[TCA_FLOWER_KEY_VLAN_PRIO, int8[0:7]]
	TCA_FLOWER_KEY_VLAN_ETH_TYPE		nlattr[TCA_FLOWER_KEY_VLAN_ETH_TYPE, flags[vlan_proto, int16be]]
	TCA_FLOWER_KEY_ENC_KEY_ID		nlattr[TCA_FLOWER_KEY_ENC_KEY_ID, int32]
	TCA_FLOWER_KEY_ENC_IPV4_SRC		nlattr[TCA_FLOWER_KEY_ENC_IPV4_SRC, ipv4_addr]
	TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK	nlattr[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, ipv4_addr_mask]
	TCA_FLOWER_KEY_ENC_IPV4_DST		nlattr[TCA_FLOWER_KEY_ENC_IPV4_DST, ipv4_addr]
	TCA_FLOWER_KEY_ENC_IPV4_DST_MASK	nlattr[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, ipv4_addr_mask]
	TCA_FLOWER_KEY_ENC_IPV6_SRC		nlattr[TCA_FLOWER_KEY_ENC_IPV6_SRC, ipv6_addr]
	TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK	nlattr[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, ipv6_addr_mask]
	TCA_FLOWER_KEY_ENC_IPV6_DST		nlattr[TCA_FLOWER_KEY_ENC_IPV6_DST, ipv6_addr]
	TCA_FLOWER_KEY_ENC_IPV6_DST_MASK	nlattr[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, ipv6_addr_mask]
	TCA_FLOWER_KEY_TCP_SRC_MASK		nlattr[TCA_FLOWER_KEY_TCP_SRC_MASK, int16[0:0]]
	TCA_FLOWER_KEY_TCP_DST_MASK		nlattr[TCA_FLOWER_KEY_TCP_DST_MASK, int16[0:0]]
	TCA_FLOWER_KEY_UDP_SRC_MASK		nlattr[TCA_FLOWER_KEY_UDP_SRC_MASK, int16[0:0]]
	TCA_FLOWER_KEY_UDP_DST_MASK		nlattr[TCA_FLOWER_KEY_UDP_DST_MASK, int16[0:0]]
	TCA_FLOWER_KEY_SCTP_SRC_MASK		nlattr[TCA_FLOWER_KEY_SCTP_SRC_MASK, int16[0:0]]
	TCA_FLOWER_KEY_SCTP_DST_MASK		nlattr[TCA_FLOWER_KEY_SCTP_DST_MASK, int16[0:0]]
	TCA_FLOWER_KEY_SCTP_SRC			nlattr[TCA_FLOWER_KEY_SCTP_SRC, int16[0:0]]
	TCA_FLOWER_KEY_SCTP_DST			nlattr[TCA_FLOWER_KEY_SCTP_DST, int16[0:0]]
	TCA_FLOWER_KEY_ENC_UDP_SRC_PORT		nlattr[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, int16[0:0]]
	TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK	nlattr[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, int16[0:0]]
	TCA_FLOWER_KEY_ENC_UDP_DST_PORT		nlattr[TCA_FLOWER_KEY_ENC_UDP_DST_PORT, int16[0:0]]
	TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK	nlattr[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, int16[0:0]]
	TCA_FLOWER_KEY_FLAGS			nlattr[TCA_FLOWER_KEY_FLAGS, int32]
	TCA_FLOWER_KEY_FLAGS_MASK		nlattr[TCA_FLOWER_KEY_FLAGS_MASK, int32]
	TCA_FLOWER_KEY_ICMPV4_CODE		nlattr[TCA_FLOWER_KEY_ICMPV4_CODE, int8[0:0]]
	TCA_FLOWER_KEY_ICMPV4_CODE_MASK		nlattr[TCA_FLOWER_KEY_ICMPV4_CODE_MASK, int8[0:0]]
	TCA_FLOWER_KEY_ICMPV4_TYPE		nlattr[TCA_FLOWER_KEY_ICMPV4_TYPE, int8[0:0]]
	TCA_FLOWER_KEY_ICMPV4_TYPE_MASK		nlattr[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, int8[0:0]]
	TCA_FLOWER_KEY_ICMPV6_CODE		nlattr[TCA_FLOWER_KEY_ICMPV6_CODE, int8[0:0]]
	TCA_FLOWER_KEY_ICMPV6_CODE_MASK		nlattr[TCA_FLOWER_KEY_ICMPV6_CODE_MASK, int8[0:0]]
	TCA_FLOWER_KEY_ICMPV6_TYPE		nlattr[TCA_FLOWER_KEY_ICMPV6_TYPE, int8[0:0]]
	TCA_FLOWER_KEY_ICMPV6_TYPE_MASK		nlattr[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, int8[0:0]]
	TCA_FLOWER_KEY_ARP_SIP			nlattr[TCA_FLOWER_KEY_ARP_SIP, ipv4_addr]
	TCA_FLOWER_KEY_ARP_SIP_MASK		nlattr[TCA_FLOWER_KEY_ARP_SIP_MASK, ipv4_addr_mask]
	TCA_FLOWER_KEY_ARP_TIP			nlattr[TCA_FLOWER_KEY_ARP_TIP, ipv4_addr]
	TCA_FLOWER_KEY_ARP_TIP_MASK		nlattr[TCA_FLOWER_KEY_ARP_TIP_MASK, ipv4_addr_mask]
	TCA_FLOWER_KEY_ARP_OP			nlattr[TCA_FLOWER_KEY_ARP_OP, int8]
	TCA_FLOWER_KEY_ARP_OP_MASK		nlattr[TCA_FLOWER_KEY_ARP_OP_MASK, int8]
	TCA_FLOWER_KEY_ARP_SHA			nlattr[TCA_FLOWER_KEY_ARP_SHA, mac_addr]
	TCA_FLOWER_KEY_ARP_SHA_MASK		nlattr[TCA_FLOWER_KEY_ARP_SHA_MASK, mac_addr_mask]
	TCA_FLOWER_KEY_ARP_THA			nlattr[TCA_FLOWER_KEY_ARP_THA, mac_addr]
	TCA_FLOWER_KEY_ARP_THA_MASK		nlattr[TCA_FLOWER_KEY_ARP_THA_MASK, mac_addr_mask]
	TCA_FLOWER_KEY_MPLS_TTL			nlattr[TCA_FLOWER_KEY_MPLS_TTL, int8]
	TCA_FLOWER_KEY_MPLS_BOS			nlattr[TCA_FLOWER_KEY_MPLS_BOS, int8]
	TCA_FLOWER_KEY_MPLS_TC			nlattr[TCA_FLOWER_KEY_MPLS_TC, int8]
	TCA_FLOWER_KEY_MPLS_LABEL		nlattr[TCA_FLOWER_KEY_MPLS_LABEL, int32]
	TCA_FLOWER_KEY_MPLS_OPTS		nlnest[TCA_FLOWER_KEY_MPLS_OPTS, mpls_opts]
	TCA_FLOWER_KEY_TCP_FLAGS		nlattr[TCA_FLOWER_KEY_TCP_FLAGS, int16]
	TCA_FLOWER_KEY_TCP_FLAGS_MASK		nlattr[TCA_FLOWER_KEY_TCP_FLAGS_MASK, int16]
	TCA_FLOWER_KEY_IP_TOS			nlattr[TCA_FLOWER_KEY_IP_TOS, int8]
	TCA_FLOWER_KEY_IP_TOS_MASK		nlattr[TCA_FLOWER_KEY_IP_TOS_MASK, int8]
	TCA_FLOWER_KEY_IP_TTL			nlattr[TCA_FLOWER_KEY_IP_TTL, int8]
	TCA_FLOWER_KEY_IP_TTL_MASK		nlattr[TCA_FLOWER_KEY_IP_TTL_MASK, int8]
	TCA_FLOWER_KEY_CVLAN_ID			nlattr[TCA_FLOWER_KEY_CVLAN_ID, int16[0:4095]]
	TCA_FLOWER_KEY_CVLAN_PRIO		nlattr[TCA_FLOWER_KEY_CVLAN_PRIO, int8[0:8]]
	TCA_FLOWER_KEY_CVLAN_ETH_TYPE		nlattr[TCA_FLOWER_KEY_CVLAN_ETH_TYPE, flags[vlan_proto, int16be]]
	TCA_FLOWER_KEY_ENC_IP_TOS		nlattr[TCA_FLOWER_KEY_ENC_IP_TOS, int8]
	TCA_FLOWER_KEY_ENC_IP_TOS_MASK		nlattr[TCA_FLOWER_KEY_ENC_IP_TOS_MASK, int8]
	TCA_FLOWER_KEY_ENC_IP_TTL		nlattr[TCA_FLOWER_KEY_ENC_IP_TTL, int8]
	TCA_FLOWER_KEY_ENC_IP_TTL_MASK		nlattr[TCA_FLOWER_KEY_ENC_IP_TTL_MASK, int8]
	TCA_FLOWER_KEY_ENC_OPTS			nlnest[TCA_FLOWER_KEY_ENC_OPTS, array[enc_opts_policy]]
	TCA_FLOWER_KEY_ENC_OPTS_MASK		nlnest[TCA_FLOWER_KEY_ENC_OPTS_MASK, array[enc_opts_policy]]
	TCA_FLOWER_KEY_PORT_SRC_MIN		nlattr[TCA_FLOWER_KEY_PORT_SRC_MIN, sock_port]
	TCA_FLOWER_KEY_PORT_SRC_MAX		nlattr[TCA_FLOWER_KEY_PORT_SRC_MAX, sock_port]
	TCA_FLOWER_KEY_PORT_DST_MIN		nlattr[TCA_FLOWER_KEY_PORT_DST_MIN, sock_port]
	TCA_FLOWER_KEY_PORT_DST_MAX		nlattr[TCA_FLOWER_KEY_PORT_DST_MAX, sock_port]
	TCA_FLOWER_KEY_CT_STATE			nlattr[TCA_FLOWER_KEY_CT_STATE, int16]
	TCA_FLOWER_KEY_CT_STATE_MASK		nlattr[TCA_FLOWER_KEY_CT_STATE_MASK, int16]
	TCA_FLOWER_KEY_CT_ZONE			nlattr[TCA_FLOWER_KEY_CT_ZONE, int16]
	TCA_FLOWER_KEY_CT_ZONE_MASK		nlattr[TCA_FLOWER_KEY_CT_ZONE_MASK, int16]
	TCA_FLOWER_KEY_CT_MARK			nlattr[TCA_FLOWER_KEY_CT_MARK, int32]
	TCA_FLOWER_KEY_CT_MARK_MASK		nlattr[TCA_FLOWER_KEY_CT_MARK_MASK, int32]
	TCA_FLOWER_KEY_CT_LABELS		nlattr[TCA_FLOWER_KEY_CT_LABELS, array[int8, 16]]
	TCA_FLOWER_KEY_CT_LABELS_MASK		nlattr[TCA_FLOWER_KEY_CT_LABELS_MASK, array[int8, 16]]
] [varlen]

enc_opts_policy [
	TCA_FLOWER_KEY_ENC_OPTS_GENEVE	nlnest[TCA_FLOWER_KEY_ENC_OPTS_GENEVE, array[geneve_opt_policy]]
	TCA_FLOWER_KEY_ENC_OPTS_VXLAN	nlnest[TCA_FLOWER_KEY_ENC_OPTS_VXLAN, array[vxlan_opt_policy]]
	TCA_FLOWER_KEY_ENC_OPTS_ERSPAN	nlnest[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN, array[erspan_opt_policy]]
] [varlen]

geneve_opt_policy [
	TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS	nlattr[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, int16]
	TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE	nlattr[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, int8]
	TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA	nlattr[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, int8]
] [varlen]

vxlan_opt_policy [
	TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP	nlattr[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, int32]
] [varlen]

erspan_opt_policy [
	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER	nlattr[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER, int8[0:1]]
	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX	nlattr[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX, int32]
	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR	nlattr[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR, int8]
	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID	nlattr[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID, int8]
] [varlen]

mpls_opts [
	TCA_FLOWER_KEY_MPLS_OPTS_LSE	nlnest[TCA_FLOWER_KEY_MPLS_OPTS_LSE, array[mpls_stack_entry_policy]]
] [varlen]

mpls_stack_entry_policy [
	TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH	nlattr[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH, int8[1:FLOW_DIS_MPLS_MAX]]
	TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL		nlattr[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL, int8]
	TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS		nlattr[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS, int8[0:MPLS_BOS_MASK]]
	TCA_FLOWER_KEY_MPLS_OPT_LSE_TC		nlattr[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC, int8[0:MPLS_TC_MASK]]
	TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL	nlattr[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL, mpls_label]
] [varlen]

fw_policy [
	TCA_FW_CLASSID	nlattr[TCA_FW_CLASSID, tcm_handle]
	TCA_FW_POLICE	nlattr[TCA_FW_POLICE, array[police_policy]]
	TCA_FW_INDEV	nlattr[TCA_FW_INDEV, devname]
	TCA_FW_ACT	nlattr[TCA_FW_ACT, array[tca_actions]]
	TCA_FW_MASK	nlattr[TCA_FW_MASK, int32]
] [varlen]

mall_policy [
	TCA_MATCHALL_CLASSID	nlattr[TCA_MATCHALL_CLASSID, tcm_handle]
	TCA_MATCHALL_ACT	nlattr[TCA_MATCHALL_ACT, array[tca_actions]]
	TCA_MATCHALL_FLAGS	nlattr[TCA_MATCHALL_FLAGS, int32[0:8]]
] [varlen]

route4_policy [
	TCA_ROUTE4_CLASSID	nlattr[TCA_ROUTE4_CLASSID, tcm_handle]
	TCA_ROUTE4_TO		nlattr[TCA_ROUTE4_TO, int32[0:256]]
	TCA_ROUTE4_FROM		nlattr[TCA_ROUTE4_FROM, int32[0:256]]
	TCA_ROUTE4_IIF		nlattr[TCA_ROUTE4_IIF, ifindex]
	TCA_ROUTE4_POLICE	nlattr[TCA_ROUTE4_POLICE, array[police_policy]]
	TCA_ROUTE4_ACT		nlattr[TCA_ROUTE4_ACT, array[tca_actions]]
] [varlen]

u32_policy [
	TCA_U32_CLASSID	nlattr[TCA_U32_CLASSID, tcm_handle]
	TCA_U32_HASH	nlattr[TCA_U32_HASH, int32]
	TCA_U32_LINK	nlattr[TCA_U32_LINK, int32]
	TCA_U32_DIVISOR	nlattr[TCA_U32_DIVISOR, int32[0:0x100]]
	TCA_U32_SEL	nlattr[TCA_U32_SEL, tc_u32_sel]
	TCA_U32_POLICE	nlattr[TCA_U32_POLICE, array[police_policy]]
	TCA_U32_ACT	nlattr[TCA_U32_ACT, array[tca_actions]]
	TCA_U32_INDEV	nlattr[TCA_U32_INDEV, devname]
	TCA_U32_MARK	nlattr[TCA_U32_MARK, tc_u32_mark]
	TCA_U32_FLAGS	nlattr[TCA_U32_FLAGS, int32[0:8]]
] [varlen]

tc_rsvp_gpi {
	key	int32
	mask	int32
	offset	int32
}

tc_rsvp_pinfo {
	dpi		tc_rsvp_gpi
	spi		tc_rsvp_gpi
	protocol	flags[ipv4_types, int8]
	tunnelid	int8
	tunnelhdr	int8
	pad		const[0, int8]
}

tc_u32_sel {
	flags		int8[0:16]
	offshift	int8
	nkeys		int8
	offmast		int16be
	off		int16
	offoff		int16
	hoff		int16
	hmask		int32be
	keys		array[tc_u32_key, 0:128]
}

# NEED: (mark.val & mark.mask) should equal to mark.val
tc_u32_mark {
	val	int32
	mask	int32
	success	const[0, int32]
}

# ------------------------------ tc action ------------------------------
type nlattr_tca_actions[PAYLOAD] nlattr_tt[int16:14[0:TCA_ACT_MAX_PRIO], 0, 0, PAYLOAD]

tca_actions [
	m_bpf		nlattr_tca_actions[tcf_action_policy["bpf", act_bpf_policy]]
	m_connmark	nlattr_tca_actions[tcf_action_policy["connmark", connmark_policy]]
	m_csum		nlattr_tca_actions[tcf_action_policy["csum", csum_policy]]
	m_ct		nlattr_tca_actions[tcf_action_policy["ct", ct_policy]]
	m_ctinfo	nlattr_tca_actions[tcf_action_policy["ctinfo", ctinfo_policy]]
	m_gact		nlattr_tca_actions[tcf_action_policy["gact", gact_policy]]
	m_ife		nlattr_tca_actions[tcf_action_policy["ife", ife_policy]]
	m_xt		nlattr_tca_actions[tcf_action_policy["xt", ipt_policy]]
	m_mirred	nlattr_tca_actions[tcf_action_policy["mirred", mirred_policy]]
	m_mpls		nlattr_tca_actions[tcf_action_policy["mpls", mpls_policy]]
	m_nat		nlattr_tca_actions[tcf_action_policy["nat", nat_policy]]
	m_pedit		nlattr_tca_actions[tcf_action_policy["pedit", pedit_policy]]
	m_police	nlattr_tca_actions[tcf_action_policy["police", array[police_policy]]]
	m_sample	nlattr_tca_actions[tcf_action_policy["sample", sample_policy]]
	m_simple	nlattr_tca_actions[tcf_action_policy["simple", simple_policy]]
	m_skbedit	nlattr_tca_actions[tcf_action_policy["skbedit", skbedit_policy]]
	m_skbmod	nlattr_tca_actions[tcf_action_policy["skbmod", skbmod_policy]]
	m_tunnel_key	nlattr_tca_actions[tcf_action_policy["tunnel_key", tunnel_key_policy]]
	m_vlan		nlattr_tca_actions[tcf_action_policy["vlan", vlan_policy$act]]
] [varlen]

type tcf_action_policy[NAME, VALUES] {
	TCA_ACT_KIND		nlattr[TCA_ACT_KIND, string[NAME]]
	TCA_ACT_OPTIONS		nlnest[TCA_ACT_OPTIONS, array[VALUES]]
	TCA_ACT_COOKIE		nlattr[TCA_ACT_COOKIE, array[int8]]
	TCA_ACT_FLAGS		nlattr[TCA_ACT_FLAGS, nla_bitfield32[tcf_action_policy_flags]]
	TCA_ACT_HW_STATS	nlattr[TCA_ACT_HW_STATS, nla_bitfield32[tcf_action_policy_hw_stats]]
} [packed, align[4]]

tcf_action_policy_flags = TCA_ACT_FLAGS_NO_PERCPU_STATS
tcf_action_policy_hw_stats = TCA_ACT_HW_STATS_IMMEDIATE, TCA_ACT_HW_STATS_DELAYED

act_bpf_policy [
	TCA_ACT_BPF_PARMS	nlattr[TCA_ACT_BPF_PARMS, tc_act_bpf]
	TCA_ACT_BPF_OPS_LEN	nlattr[TCA_ACT_BPF_OPS_LEN, int16[0:10]]
	TCA_ACT_BPF_OPS		nlattr[TCA_ACT_BPF_OPS, array[sock_filter]]
	TCA_ACT_BPF_FD		nlattr[TCA_ACT_BPF_FD, fd]
	TCA_ACT_BPF_NAME	nlattr[TCA_ACT_BPF_NAME, string[filename]]
] [varlen]

connmark_policy [
	TCA_CONNMARK_PARMS	nlattr[TCA_CONNMARK_PARMS, tc_connmark]
] [varlen]

csum_policy [
	TCA_CSUM_PARMS	nlattr[TCA_CSUM_PARMS, tc_csum]
] [varlen]

ct_policy [
	TCA_CT_PARMS		nlattr[TCA_CT_PARMS, tc_gen]
	TCA_CT_ACTION		nlattr[TCA_CT_ACTION, flags[tca_ct_actions, int16]]
	TCA_CT_ZONE		nlattr[TCA_CT_ZONE, int16]
	TCA_CT_MARK		nlattr[TCA_CT_MARK, int32]
	TCA_CT_MARK_MASK	nlattr[TCA_CT_MARK_MASK, int32]
	TCA_CT_LABELS		nlattr[TCA_CT_LABELS, array[int8, 16]]
	TCA_CT_LABELS_MASK	nlattr[TCA_CT_LABELS_MASK, array[int8, 16]]
	TCA_CT_NAT_IPV4_MIN	nlattr[TCA_CT_NAT_IPV4_MIN, ipv4_addr]
	TCA_CT_NAT_IPV4_MAX	nlattr[TCA_CT_NAT_IPV4_MAX, ipv4_addr]
	TCA_CT_NAT_IPV6_MIN	nlattr[TCA_CT_NAT_IPV6_MIN, ipv6_addr]
	TCA_CT_NAT_IPV6_MAX	nlattr[TCA_CT_NAT_IPV6_MAX, ipv6_addr]
	TCA_CT_NAT_PORT_MIN	nlattr[TCA_CT_NAT_PORT_MIN, sock_port]
	TCA_CT_NAT_PORT_MAX	nlattr[TCA_CT_NAT_PORT_MAX, sock_port]
] [varlen]

ctinfo_policy [
	TCA_CTINFO_ACT			nlattr[TCA_CTINFO_ACT, tc_gen]
	TCA_CTINFO_ZONE			nlattr[TCA_CTINFO_ZONE, int16]
	TCA_CTINFO_PARMS_DSCP_MASK	nlattr[TCA_CTINFO_PARMS_DSCP_MASK, int32]
	TCA_CTINFO_PARMS_DSCP_STATEMASK	nlattr[TCA_CTINFO_PARMS_DSCP_STATEMASK, int32]
	TCA_CTINFO_PARMS_CPMARK_MASK	nlattr[TCA_CTINFO_PARMS_CPMARK_MASK, int32]
] [varlen]

gact_policy [
	TCA_GACT_PARMS	nlattr[TCA_GACT_PARMS, tc_gen]
	TCA_GACT_PROB	nlattr[TCA_GACT_PROB, tc_gact_p]
] [varlen]

ife_policy [
	TCA_IFE_PARMS	nlattr[TCA_IFE_PARMS, tc_ife]
	TCA_IFE_DMAC	nlattr[TCA_IFE_DMAC, mac_addr]
	TCA_IFE_SMAC	nlattr[TCA_IFE_SMAC, mac_addr]
	TCA_IFE_TYPE	nlattr[TCA_IFE_TYPE, int16]
	TCA_IFE_METALST	nlattr[TCA_IFE_METALST, array[tca_ife_meta_policy]]
] [varlen]

tca_ife_meta_policy [
	IFE_META_SKBMARK	nlattr[IFE_META_SKBMARK, optional[int32]]
	IFE_META_PRIO		nlattr[IFE_META_PRIO, optional[int32]]
	IFE_META_TCINDEX	nlattr[IFE_META_TCINDEX, optional[int16]]
] [varlen]

# NEED: u_target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size
xt_entry_target {
	u_target_size	int16
	name		string[ipt_tables, XT_TABLE_MAXNAMELEN]
	revision	int8
	target_size	int16
	data		array[int8]
}

mirred_policy [
	TCA_MIRRED_PARMS	nlattr[TCA_MIRRED_PARMS, tc_mirred]
] [varlen]

mpls_policy [
	TCA_MPLS_PARMS	nlattr[TCA_MPLS_PARMS, tc_mpls]
	TCA_MPLS_PROTO	nlattr[TCA_MPLS_PROTO, flags[ether_types, int16be]]
	TCA_MPLS_LABEL	nlattr[TCA_MPLS_LABEL, int32[0:0xfffff]]
	TCA_MPLS_TC	nlattr[TCA_MPLS_TC, int8[0:7]]
	TCA_MPLS_TTL	nlattr[TCA_MPLS_TTL, int8]
	TCA_MPLS_BOS	nlattr[TCA_MPLS_BOS, int8[0:1]]
] [varlen]

nat_policy [
	TCA_NAT_PARMS	nlattr[TCA_NAT_PARMS, tc_nat]
] [varlen]

pedit_policy [
	TCA_PEDIT_PARMS		nlattr[TCA_PEDIT_PARMS, m_pedit_sel]
	TCA_PEDIT_PARMS_EX	nlattr[TCA_PEDIT_PARMS_EX, m_pedit_sel]
	TCA_PEDIT_KEYS_EX	nlnest[TCA_PEDIT_KEYS_EX, array[nlnest[TCA_PEDIT_KEY_EX, array[pedit_key_ex_policy]]]]
] [varlen]

pedit_key_ex_policy [
	TCA_PEDIT_KEY_EX_HTYPE	nlattr[TCA_PEDIT_KEY_EX_HTYPE, flags[pedit_header_type, int16]]
	TCA_PEDIT_KEY_EX_CMD	nlattr[TCA_PEDIT_KEY_EX_CMD, flags[pedit_cmd, int16]]
] [varlen]

sample_policy [
	TCA_SAMPLE_PARMS		nlattr[TCA_SAMPLE_PARMS, tc_gen]
	TCA_SAMPLE_RATE			nlattr[TCA_SAMPLE_RATE, int32]
	TCA_SAMPLE_TRUNC_SIZE		nlattr[TCA_SAMPLE_TRUNC_SIZE, int32]
	TCA_SAMPLE_PSAMPLE_GROUP	nlattr[TCA_SAMPLE_PSAMPLE_GROUP, int32]
] [varlen]

simple_policy [
	TCA_DEF_PARMS	nlattr[TCA_DEF_PARMS, tc_gen]
	TCA_DEF_DATA	nlattr[TCA_DEF_DATA, string]
] [varlen]

skbedit_policy [
	TCA_SKBEDIT_PARMS		nlattr[TCA_SKBEDIT_PARMS, tc_gen]
	TCA_SKBEDIT_QUEUE_MAPPING	nlattr[TCA_SKBEDIT_QUEUE_MAPPING, int16]
	TCA_SKBEDIT_PRIORITY		nlattr[TCA_SKBEDIT_PRIORITY, tcm_handle]
	TCA_SKBEDIT_MARK		nlattr[TCA_SKBEDIT_MARK, int32]
	TCA_SKBEDIT_PTYPE		nlattr[TCA_SKBEDIT_PTYPE, flags[packet_types, int16]]
] [varlen]

skbmod_policy [
	TCA_SKBMOD_PARMS	nlattr[TCA_SKBMOD_PARMS, tc_skbmod]
	TCA_SKBMOD_DMAC		nlattr[TCA_SKBMOD_DMAC, mac_addr]
	TCA_SKBMOD_SMAC		nlattr[TCA_SKBMOD_SMAC, mac_addr]
	TCA_SKBMOD_ETYPE	nlattr[TCA_SKBMOD_ETYPE, int16]
] [varlen]

tunnel_key_policy [
	TCA_TUNNEL_KEY_PARMS		nlattr[TCA_TUNNEL_KEY_PARMS, tc_tunnel_key]
	TCA_TUNNEL_KEY_ENC_IPV4_SRC	nlattr[TCA_TUNNEL_KEY_ENC_IPV4_SRC, ipv4_addr]
	TCA_TUNNEL_KEY_ENC_IPV4_DST	nlattr[TCA_TUNNEL_KEY_ENC_IPV4_DST, ipv4_addr]
	TCA_TUNNEL_KEY_ENC_IPV6_SRC	nlattr[TCA_TUNNEL_KEY_ENC_IPV6_SRC, ipv6_addr]
	TCA_TUNNEL_KEY_ENC_IPV6_DST	nlattr[TCA_TUNNEL_KEY_ENC_IPV6_DST, ipv6_addr]
	TCA_TUNNEL_KEY_ENC_KEY_ID	nlattr[TCA_TUNNEL_KEY_ENC_KEY_ID, int32]
	TCA_TUNNEL_KEY_ENC_DST_PORT	nlattr[TCA_TUNNEL_KEY_ENC_DST_PORT, sock_port]
	TCA_TUNNEL_KEY_NO_CSUM		nlattr[TCA_TUNNEL_KEY_NO_CSUM, int8[0:1]]
] [varlen]

vlan_policy$act [
	TCA_VLAN_PARMS			nlattr[TCA_VLAN_PARMS, tc_vlan]
	TCA_VLAN_PUSH_VLAN_ID		nlattr[TCA_VLAN_PUSH_VLAN_ID, int16[0:0xfff]]
	TCA_VLAN_PUSH_VLAN_PROTOCOL	nlattr[TCA_VLAN_PUSH_VLAN_PROTOCOL, flags[vlan_proto, int16be]]
	TCA_VLAN_PUSH_VLAN_PRIORITY	nlattr[TCA_VLAN_PUSH_VLAN_PRIORITY, int8[0:7]]
] [varlen]

action_gd_policy [
	TCA_ACT_TAB	nlattr[TCA_ACT_TAB, array[nlattr_tca_actions[tcf_action_policy$kind_index]]]
] [varlen]

tcf_action_policy$kind_index [
	TCA_ACT_KIND	nlattr[TCA_ACT_KIND, string[tca_actions_kinds]]
	TCA_ACT_INDEX	nlattr[TCA_ACT_INDEX, int32]
] [varlen]

tcaa_policy [
	TCA_ROOT_FLAGS		nlattr[TCA_ROOT_FLAGS, nla_bitfield32[tcaa_policy_root_flags]]
	TCA_ROOT_TIME_DELTA	nlattr[TCA_ROOT_TIME_DELTA, int32]
] [varlen]

tcaa_policy_root_flags = TCA_FLAG_LARGE_DUMP_ON

action_dump_policy [
	action_gd		action_gd_policy
	action_dump_flags	tcaa_policy
] [varlen]

tc_gen {
	index	int32
	capab	int32
	action	flags[tc_actions, int32]
	refcnt	int32
	bindcnt	int32
}

type tc_act_bpf tc_gen

tc_connmark {
	tc_gen	tc_gen
	zone	int16
}

tc_csum {
	tc_gen		tc_gen
	update_flags	int32[0:128]
}

tc_gact_p {
	ptype	flags[tc_pgact_flags, int16]
	pval	int16[0:10000]
	paction	flags[tc_actions, int32]
}

tc_ife {
	tc_gen	tc_gen
	flags	int16[0:1]
}

tc_mirred {
	tc_gen	tc_gen
	eaction	flags[tc_mirred_eactions, int32]
	ifindex	ifindex
}

tc_mpls {
	tc_gen		tc_gen
	m_action	flags[tca_mpls_actions, int32]
}

tc_nat {
	tc_gen		tc_gen
	old_addr	ipv4_addr
	new_addr	ipv4_addr
	mask		ipv4_addr_mask
	flags		int32[0:1]
}

m_pedit_sel {
	sel		tc_pedit_sel
	keys		array[tc_pedit_key, 128]
	keys_ex		array[m_pedit_key_ex, 128]
	extended	bool8
} [packed, align[4]]

tc_pedit_sel {
	tc_gen	tc_gen
	nkeys	int8
	flags	int8
	keys	array[tc_pedit_key]
}

tc_pedit_key {
	mask	int32
	val	int32
	off	int32
	at	int32
	offmask	int32
	shift	int32
}

m_pedit_key_ex {
	htype	flags[pedit_header_type, int16]
	cmd	flags[pedit_cmd, int16]
}

tc_skbmod {
	tc_gen	tc_gen
	flags	int64[0:16]
}

tc_tunnel_key {
	tc_gen		tc_gen
	t_action	int32[1:2]
}

tc_vlan {
	tc_gen		tc_gen
	v_action	int32[1:3]
}

# ------------------------------ tc police ------------------------------
police_policy [
	TCA_POLICE_TBF		nlattr[TCA_POLICE_TBF, tc_police]
	TCA_POLICE_RATE		nlattr[TCA_POLICE_RATE, array[int32, 256]]
	TCA_POLICE_PEAKRATE	nlattr[TCA_POLICE_PEAKRATE, array[int32, 256]]
	TCA_POLICE_AVRATE	nlattr[TCA_POLICE_AVRATE, int32]
	TCA_POLICE_RESULT	nlattr[TCA_POLICE_RESULT, int32]
	TCA_POLICE_RATE64	nlattr[TCA_POLICE_RATE64, int64]
	TCA_POLICE_PEAKRATE64	nlattr[TCA_POLICE_PEAKRATE64, int64]
] [varlen]

tc_police {
	index		int32
	action		flags[tc_actions, int32]
	limit		int32
	burst		int32
	mtu		int32
	rate		tc_ratespec
	peakrate	tc_ratespec
	refcnt		int32
	bindcnt		int32
	capab		int32
}

tc_ratespec {
	cell_log	int8
	linklayer	flags[linklayer, int8]
	overhead	int16
	cell_align	int16
	mpu		int16
	rate		int32
}

# ------------------------------ tc ematch ------------------------------
em_policy [
	TCA_EMATCH_TREE_HDR	nlattr[TCA_EMATCH_TREE_HDR, tcf_ematch_tree_hdr]
	TCA_EMATCH_TREE_LIST	nlnest[TCA_EMATCH_TREE_LIST, array[tca_ematch_tree_list]]
] [varlen]

tcf_ematch_tree_hdr {
	nmatches	int16
	progid		const[TCF_EM_PROG_TC, int16]
}

type nlattr_tca_ematch_tree_list[PAYLOAD] nlattr_tt[int16:14[1:3], 0, 0, PAYLOAD]

tca_ematch_tree_list [
	TCF_EM_CONTAINER	nlattr_tca_ematch_tree_list[tcf_ematch_hdr_t[TCF_EM_CONTAINER, array[int8]]]
	TCF_EM_CMP		nlattr_tca_ematch_tree_list[tcf_ematch_hdr_t[TCF_EM_CMP, tcf_em_cmp]]
	TCF_EM_NBYTE		nlattr_tca_ematch_tree_list[tcf_ematch_hdr_t[TCF_EM_NBYTE, tcf_em_nbyte]]
	TCF_EM_U32		nlattr_tca_ematch_tree_list[tcf_ematch_hdr_t[TCF_EM_U32, tc_u32_key]]
	TCF_EM_META		nlattr_tca_ematch_tree_list[tcf_ematch_hdr_t[TCF_EM_META, array[meta_policy]]]
	TCF_EM_CANID		nlattr_tca_ematch_tree_list[tcf_ematch_hdr_t[TCF_EM_CANID, can_filter]]
	TCF_EM_IPSET		nlattr_tca_ematch_tree_list[tcf_ematch_hdr_t[TCF_EM_IPSET, xt_set_info]]
	TCF_EM_IPT		nlattr_tca_ematch_tree_list[tcf_ematch_hdr_t[TCF_EM_IPT, array[em_ipt_policy]]]
] [varlen]

type tcf_ematch_hdr[KIND] {
	matchid	int16
	kind	const[KIND, int16]
	flags	int16
	pad	const[0, int16]
} [align[4]]

type tcf_ematch_hdr_t[KIND, PAYLOAD] {
	header	tcf_ematch_hdr[KIND]
	payload	PAYLOAD
} [align[4]]

tcf_em_cmp {
	val	int32
	mask	int32
	off	int16
	align	flags[tcf_em_aligns, int8:4]
	flags	int8:4
	layer	flags[tcf_layers, int8:4]
	opnd	flags[tcf_em_opnds, int8:4]
}

tcf_em_nbyte {
	off	int16
	len	bytesize[payload, int16:12]
	layer	flags[tcf_layers, int8:4]
	payload	array[int8, 0:10]
} [align[4]]

tc_u32_key {
	mask	int32be
	val	int32be
	off	int32
	offmask	int32
}

meta_policy [
	TCA_EM_META_HDR		nlattr[TCA_EM_META_HDR, tcf_meta_hdr]
	TCA_EM_META_LVALUE	nlattr[TCA_EM_META_LVALUE, array[tcf_em_meta_int_var]]
	TCA_EM_META_RVALUE	nlattr[TCA_EM_META_RVALUE, array[tcf_em_meta_int_var]]
] [varlen]

tcf_meta_hdr {
	left	tcf_meta_val
	right	tcf_meta_val
}

tcf_meta_val {
# TODO: kind value should be TCF_META_TYPE_VAR << 12 or TCF_META_TYPE_INT << 12
	kind	int16
	shift	int8
	op	flags[tcf_em_opnds, int8]
}

tcf_em_meta_int_var [
	TCF_META_TYPE_INT	int32[0:10]
	TCF_META_TYPE_VAR	array[int8, 0:10]
] [varlen]

em_ipt_policy [
	TCA_EM_IPT_HOOK			nlattr[TCA_EM_IPT_HOOK, flags[nf_inet_hooks, int32]]
	TCA_EM_IPT_MATCH_NAME		nlattr[TCA_EM_IPT_MATCH_NAME, string["policy"]]
	TCA_EM_IPT_MATCH_REVISION	nlattr[TCA_EM_IPT_MATCH_REVISION, int8]
	TCA_EM_IPT_NFPROTO		nlattr[TCA_EM_IPT_NFPROTO, flags[nfproto, int8]]
	TCA_EM_IPT_MATCH_DATA		nlattr[TCA_EM_IPT_MATCH_DATA, array[int8]]
] [varlen]

# ------------------------------ tc others ------------------------------
tc_estimator {
	interval	int8
	ewma_log	int8
}

stab_policy {
	TCA_STAB_BASE	nlattr[TCA_STAB_BASE, tc_sizespec]
	TCA_STAB_DATA	nlattr[TCA_STAB_DATA, array[int16]]
} [packed]

tc_sizespec {
	cell_log	int8
	size_log	int8
	cell_align	int16
	overhead	int32
	linklayer	flags[linklayer, int32]
	mpu		int32
	mtu		int32
	tsize		len[stab_policy:TCA_STAB_DATA:payload, int32]
}

tcm_handle_offsets = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0xffe0, 0xfff1, 0xfff2, 0xfff3, 0xffff
tcf_em_aligns = TCF_EM_ALIGN_U8, TCF_EM_ALIGN_U16, TCF_EM_ALIGN_U32
tcf_layers = TCF_LAYER_LINK, TCF_LAYER_NETWORK, TCF_LAYER_TRANSPORT
tcf_em_opnds = TCF_EM_OPND_EQ, TCF_EM_OPND_GT, TCF_EM_OPND_LT
nf_inet_hooks = NF_INET_PRE_ROUTING, NF_INET_LOCAL_IN, NF_INET_FORWARD, NF_INET_LOCAL_OUT, NF_INET_POST_ROUTING
linklayer = TC_LINKLAYER_UNAWARE, TC_LINKLAYER_ETHERNET, TC_LINKLAYER_ATM
tc_actions = TC_ACT_UNSPEC, TC_ACT_OK, TC_ACT_RECLASSIFY, TC_ACT_SHOT, TC_ACT_PIPE, TC_ACT_STOLEN, TC_ACT_QUEUED, TC_ACT_REPEAT, TC_ACT_REDIRECT, TC_ACT_TRAP, TC_ACT_JUMP, TC_ACT_GOTO_CHAIN
tca_actions_kinds = "bpf", "connmark", "csum", "gact", "ife", "ipt", "mirred", "nat", "pedit", "police", "sample", "skbedit", "skbmod", "tunnel_key", "vlan", "xt"
tc_flow_modes = FLOW_MODE_MAP, FLOW_MODE_HASH
tca_dsmark_ind = 1, 2, 4, 8, 16, 32
tc_mqprio_modes = TC_MQPRIO_MODE_DCB, TC_MQPRIO_MODE_CHANNEL
tc_mqprio_shapers = TC_MQPRIO_SHAPER_DCB, TC_MQPRIO_SHAPER_BW_RATE
tc_pgact_flags = PGACT_NONE, PGACT_NETRAND, PGACT_DETERM
tc_mirred_eactions = TCA_EGRESS_REDIR, TCA_EGRESS_MIRROR, TCA_INGRESS_REDIR, TCA_INGRESS_MIRROR
pedit_header_type = TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK, TCA_PEDIT_KEY_EX_HDR_TYPE_ETH, TCA_PEDIT_KEY_EX_HDR_TYPE_IP4, TCA_PEDIT_KEY_EX_HDR_TYPE_IP6, TCA_PEDIT_KEY_EX_HDR_TYPE_TCP, TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
pedit_cmd = TCA_PEDIT_KEY_EX_CMD_SET, TCA_PEDIT_KEY_EX_CMD_ADD
packet_types = PACKET_HOST, PACKET_BROADCAST, PACKET_MULTICAST, PACKET_OTHERHOST, PACKET_OUTGOING, PACKET_LOOPBACK, PACKET_USER, PACKET_KERNEL
vlan_proto = ETH_P_8021Q, ETH_P_8021AD
tc_cake_ack_filter = CAKE_ACK_NONE, CAKE_ACK_FILTER, CAKE_ACK_AGGRESSIVE
tc_cake_atm = CAKE_ATM_NONE, CAKE_ATM_ATM, CAKE_ATM_PTM
tc_cake_diffserv_mode = CAKE_DIFFSERV_DIFFSERV3, CAKE_DIFFSERV_DIFFSERV4, CAKE_DIFFSERV_DIFFSERV8, CAKE_DIFFSERV_BESTEFFORT, CAKE_DIFFSERV_PRECEDENCE
tc_cake_flow_mode = CAKE_FLOW_NONE, CAKE_FLOW_SRC_IP, CAKE_FLOW_DST_IP, CAKE_FLOW_HOSTS, CAKE_FLOW_FLOWS, CAKE_FLOW_DUAL_SRC, CAKE_FLOW_DUAL_DST, CAKE_FLOW_TRIPLE
tc_etf_clock_id = CLOCK_REALTIME, CLOCK_TAI, CLOCK_BOOTTIME, CLOCK_MONOTONIC
tc_etf_flags = TC_ETF_DEADLINE_MODE_ON, TC_ETF_OFFLOAD_ON, TC_ETF_SKIP_SOCK_CHECK
tc_plug_actions = TCQ_PLUG_BUFFER, TCQ_PLUG_RELEASE_ONE, TCQ_PLUG_RELEASE_INDEFINITE, TCQ_PLUG_LIMIT
tc_flower_flags = TCA_CLS_FLAGS_SKIP_HW, TCA_CLS_FLAGS_SKIP_SW, TCA_CLS_FLAGS_IN_HW, TCA_CLS_FLAGS_NOT_IN_HW, TCA_CLS_FLAGS_VERBOSE
tca_ct_actions = TCA_CT_ACT_COMMIT, TCA_CT_ACT_FORCE, TCA_CT_ACT_CLEAR, TCA_CT_ACT_NAT, TCA_CT_ACT_NAT_SRC, TCA_CT_ACT_NAT_DST
tca_mpls_actions = TCA_MPLS_ACT_POP, TCA_MPLS_ACT_PUSH, TCA_MPLS_ACT_MODIFY, TCA_MPLS_ACT_DEC_TTL
