# 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 <uapi/linux/if.h>
include <uapi/linux/netlink.h>
include <uapi/linux/rtnetlink.h>
include <uapi/linux/netfilter.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_connmark.h>
include <uapi/linux/tc_act/tc_csum.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_ipt.h>
include <uapi/linux/tc_act/tc_mirred.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], qdisc_policy]
	delqdisc	netlink_msg[RTM_DELQDISC, tcmsg[AF_UNSPEC], qdisc_policy]
	getqdisc	netlink_msg[RTM_GETQDISC, tcmsg[AF_UNSPEC], nlattr[TCA_DUMP_INVISIBLE, void]]
	newtclass	netlink_msg[RTM_NEWTCLASS, tcmsg[AF_UNSPEC], tclass_policy]
	deltclass	netlink_msg[RTM_DELTCLASS, tcmsg[AF_UNSPEC], tclass_policy]
	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]]
	newtaction	netlink_msg[RTM_NEWACTION, tcamsg[AF_UNSPEC], nlattr[TCA_ACT_TAB, 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]
	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	int8
	tca__pad2	int16
}

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

tclass_policy [
	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_cbq			tca_kind_options_t["cbq", array[q_cbq_options]]
	q_cbs			tca_kind_options_t["cbs", q_cbs_options]
	q_choke			tca_kind_options_t["choke", array[q_choke_options]]
	q_codel			tca_kind_options_t["codel", array[q_codel_options]]
	q_dsmark		tca_kind_options_t["dsmark", array[q_dsmark_options]]
	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[q_fq_options]]
	q_fq_codel		tca_kind_options_t["fq_codel", array[q_fq_codel_options]]
	q_gred			tca_kind_options_t["gred", array[q_gred_options]]
	q_hfsc			tca_kind_options_t["hfsc", int16]
	q_hhf			tca_kind_options_t["hhf", array[q_hhf_options]]
	q_htb			tca_kind_options_t["htb", array[q_htb_options]]
	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[q_pie_options]]
	q_prio			tca_kind_options_t["prio", tc_prio_qopt]
	q_red			tca_kind_options_t["red", array[q_red_options]]
	q_sfb			tca_kind_options_t["sfb", q_sfb_options]
	q_sfq			tca_kind_options_t["sfq", tc_sfq_qopt_v1]
	q_tbf			tca_kind_options_t["tbf", array[q_tbf_options]]
] [varlen]

q_cbq_options [
	TCA_CBQ_LSSOPT	nlattr[TCA_CBQ_LSSOPT, tc_cbq_lssopt]
	TCA_CBQ_WRROPT	nlattr[TCA_CBQ_WRROPT, tc_cbq_wrropt]
	TCA_CBQ_FOPT	nlattr[TCA_CBQ_FOPT, tc_cbq_fopt]
	TCA_CBQ_RATE	nlattr[TCA_CBQ_RATE, tc_ratespec]
	TCA_CBQ_RTAB	nlattr[TCA_CBQ_RTAB, array[int32, 256]]
] [varlen]

q_cbs_options [
	TCA_CBS_PARMS	nlattr[TCA_CBS_PARMS, tc_cbs_qopt]
] [varlen]

q_choke_options [
	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]

q_codel_options [
	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]

q_dsmark_options [
	TCA_DSMARK_INDICES		nlattr[TCA_DSMARK_INDICES, flags[tca_dsmark_ind, int16]]
	TCA_DSMARK_DEFAULT_INDEX	nlattr[TCA_DSMARK_DEFAULT_INDEX, int16]
	TCA_DSMARK_SET_TC_INDEX		nlattr[TCA_DSMARK_SET_TC_INDEX, void]
] [varlen]

q_fq_options [
	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]
] [varlen]

q_fq_codel_options [
	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]
] [varlen]

# TODO: we should not have TCA_GRED_PARMS and TCA_GRED_STAB when do init
q_gred_options [
	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]

q_hhf_options [
	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]

q_htb_options [
	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[q_mqprio_options]
}

q_mqprio_options [
	TCA_MQPRIO_MODE		nlattr[TCA_MQPRIO_MODE, flags[tc_mqprio_modes, int32]]
	TCA_MQPRIO_SHAPER	nlattr[TCA_MQPRIO_SHAPER, flags[tc_mqprio_shapers, int32]]
	TCA_MQPRIO_MIN_RATE64	nlattr[TCA_MQPRIO_MIN_RATE64, array[nlattr[TCA_MQPRIO_MIN_RATE64, int64], 0:16]]
	TCA_MQPRIO_MAX_RATE64	nlattr[TCA_MQPRIO_MAX_RATE64, array[nlattr[TCA_MQPRIO_MAX_RATE64, int64], 0:16]]
] [varlen]

tc_netem_message {
	qopt	tc_netem_qopt
	attrs	array[q_netem_options]
}

q_netem_options [
	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		nlattr[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]

q_pie_options [
	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]

q_red_options [
	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]
] [varlen]

q_sfb_options [
	TCA_SFB_PARMS	nlattr[TCA_SFB_PARMS, tc_sfb_qopt]
] [varlen]

q_tbf_options [
	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_cbq_lssopt {
	change		int8[0:64]
	flags		int8[0:3]
	ewma_log	int8[0:32]
	level		int8
	maxidle		int32
	minidle		int32
	offtime		int32
	avpkt		int32
}

tc_cbq_wrropt {
	flags		int8
	priority	int8[0:TC_CBQ_MAXPRIO]
	cpriority	int8
	__reserved	int8
	allot		int32
	weight		int32
}

tc_cbq_fopt {
	split		tcm_handle
	defmap		int32
	defchange	int32
}

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

# TODO: 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	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
	prio_tc_map	array[int8, 16]
	hw		int8
	count		array[int16, TC_QOPT_MAX_QUEUE]
	offset		array[int16, TC_QOPT_MAX_QUEUE]
}

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
}

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, 16]
}

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]
	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_atm		tca_kind_options_t["atm", array[c_atm_options]]
	c_cbq		tca_kind_options_t["cbq", array[c_cbq_options]]
	c_drr		tca_kind_options_t["drr", c_drr_options]
	c_dsmark	tca_kind_options_t["dsmark", c_dsmark_options]
	c_hfsc		tca_kind_options_t["hfsc", array[c_hfsc_options]]
	c_htb		tca_kind_options_t["htb", array[c_htb_options]]
	c_qfq		tca_kind_options_t["qfq", array[c_qfq_options]]
] [varlen]

c_atm_options [
	TCA_ATM_FD	nlattr[TCA_ATM_FD, sock]
	TCA_ATM_HDR	nlattr[TCA_ATM_HDR, array[int8, 0:64]]
	TCA_ATM_EXCESS	nlattr[TCA_ATM_EXCESS, tcm_handle]
] [varlen]

type c_cbq_options q_cbq_options

c_drr_options [
	TCA_DRR_QUANTUM	nlattr[TCA_DRR_QUANTUM, int32]
] [varlen]

c_dsmark_options [
	TCA_DSMARK_MASK		nlattr[TCA_DSMARK_MASK, int8]
	TCA_DSMARK_VALUE	nlattr[TCA_DSMARK_VALUE, int8]
] [varlen]

c_hfsc_options [
	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]

c_htb_options [
	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]
] [varlen]

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

tc_service_curve {
	m1	int32
	d	int32
	m2	int32
}

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[f_basic_options]]
	f_bpf		tca_kind_options_t["bpf", array[f_bpf_options]]
	f_cgroup	tca_kind_options_t["cgroup", array[f_cgroup_options]]
	f_flow		tca_kind_options_t["flow", array[f_flow_options]]
	f_fw		tca_kind_options_t["fw", array[f_fw_options]]
	f_matchall	tca_kind_options_t["matchall", array[f_matchall_options]]
	f_route		tca_kind_options_t["route", array[f_route_options]]
	f_rsvp		tca_kind_options_t["rsvp", array[f_rfvp_options]]
	f_rsvp6		tca_kind_options_t["rsvp6", array[f_rfvp6_options]]
	f_tcindex	tca_kind_options_t["tcindex", array[f_tcindex_options]]
	f_u32		tca_kind_options_t["u32", array[f_u32_options]]
] [varlen]

f_basic_options [
	TCA_BASIC_CLASSID	nlattr[TCA_BASIC_CLASSID, tcm_handle]
	TCA_BASIC_EMATCHES	nlattr[TCA_BASIC_EMATCHES, array[tca_ematches]]
	TCA_BASIC_ACT		nlattr[TCA_BASIC_ACT, tca_actions]
	TCA_BASIC_POLICE	nlattr[TCA_BASIC_POLICE, tca_polices]
] [varlen]

f_bpf_options [
	TCA_BPF_ACT		nlattr[TCA_BPF_ACT, tca_actions]
	TCA_BPF_POLICE		nlattr[TCA_BPF_POLICE, tca_polices]
	TCA_BPF_CLASSID		nlattr[TCA_BPF_CLASSID, tcm_handle]
# TODO: TCA_BPF_OPS should equal to TCA_BPF_OPS_LEN * sizeof(struct sock_filter)
	TCA_BPF_OPS_LEN		nlattr[TCA_BPF_OPS_LEN, int16[0:10]]
	TCA_BPF_OPS		nlattr[TCA_BPF_OPS, array[sock_filter]]
	TCA_BPF_FD		nlattr[TCA_BPF_FD, fd]
	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]

f_cgroup_options [
	TCA_CGROUP_ACT		nlattr[TCA_CGROUP_ACT, tca_actions]
	TCA_CGROUP_POLICE	nlattr[TCA_CGROUP_POLICE, tca_polices]
	TCA_CGROUP_EMATCHES	nlattr[TCA_CGROUP_EMATCHES, array[tca_ematches]]
] [varlen]

f_flow_options [
	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		nlattr[TCA_FLOW_ACT, tca_actions]
	TCA_FLOW_POLICE		nlattr[TCA_FLOW_POLICE, tca_polices]
	TCA_FLOW_EMATCHES	nlattr[TCA_FLOW_EMATCHES, array[tca_ematches]]
	TCA_FLOW_PERTURB	nlattr[TCA_FLOW_PERTURB, int32]
] [varlen]

f_fw_options [
	TCA_FW_CLASSID	nlattr[TCA_FW_CLASSID, tcm_handle]
	TCA_FW_POLICE	nlattr[TCA_FW_POLICE, tca_polices]
	TCA_FW_INDEV	nlattr[TCA_FW_INDEV, devname]
	TCA_FW_ACT	nlattr[TCA_FW_ACT, tca_actions]
	TCA_FW_MASK	nlattr[TCA_FW_MASK, int32]
] [varlen]

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

f_route_options [
	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, devname]
	TCA_ROUTE4_POLICE	nlattr[TCA_ROUTE4_POLICE, tca_polices]
	TCA_ROUTE4_ACT		nlattr[TCA_ROUTE4_ACT, tca_actions]
] [varlen]

f_rfvp_options [
	TCA_RSVP_CLASSID	nlattr[TCA_RSVP_CLASSID, tcm_handle]
	TCA_RSVP_DST		nlattr[TCA_RSVP_DST, ipv4_addr]
	TCA_RSVP_SRC		nlattr[TCA_RSVP_SRC, ipv4_addr]
	TCA_RSVP_PINFO		nlattr[TCA_RSVP_PINFO, tc_rsvp_pinfo]
	TCA_RSVP_POLICE		nlattr[TCA_RSVP_POLICE, tca_polices]
	TCA_RSVP_ACT		nlattr[TCA_RSVP_ACT, tca_actions]
] [varlen]

f_rfvp6_options [
	TCA_RSVP_CLASSID	nlattr[TCA_RSVP_CLASSID, tcm_handle]
	TCA_RSVP_DST		nlattr[TCA_RSVP_DST, ipv6_addr]
	TCA_RSVP_SRC		nlattr[TCA_RSVP_SRC, ipv6_addr]
	TCA_RSVP_PINFO		nlattr[TCA_RSVP_PINFO, tc_rsvp_pinfo]
	TCA_RSVP_POLICE		nlattr[TCA_RSVP_POLICE, tca_polices]
	TCA_RSVP_ACT		nlattr[TCA_RSVP_ACT, tca_actions]
] [varlen]

f_tcindex_options [
	TCA_TCINDEX_HASH		nlattr[TCA_TCINDEX_HASH, int32[0:0x10000]]
	TCA_TCINDEX_MASK		nlattr[TCA_TCINDEX_MASK, int16]
	TCA_TCINDEX_SHIFT		nlattr[TCA_TCINDEX_SHIFT, int32]
	TCA_TCINDEX_FALL_THROUGH	nlattr[TCA_TCINDEX_FALL_THROUGH, int32[0:1]]
	TCA_TCINDEX_CLASSID		nlattr[TCA_TCINDEX_CLASSID, tcm_handle]
	TCA_TCINDEX_POLICE		nlattr[TCA_TCINDEX_POLICE, tca_polices]
	TCA_TCINDEX_ACT			nlattr[TCA_TCINDEX_ACT, tca_actions]
] [varlen]

f_u32_options [
	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, tca_polices]
	TCA_U32_ACT	nlattr[TCA_U32_ACT, 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		int8
}

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

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

# ------------------------------ tc action ------------------------------
tca_actions [
	m_bpf		nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["bpf", array[m_bpf_options]]]
	m_connmark	nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["connmark", m_connmark_options]]
	m_csum		nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["csum", m_csum_options]]
	m_gact		nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["gact", array[m_gact_options]]]
	m_ife		nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["ife", array[m_ife_options]]]
	m_ipt		nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["ipt", array[m_ipt_options]]]
	m_mirred	nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["mirred", m_mirred_options]]
	m_nat		nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["nat", m_nat_options]]
	m_pedit		nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["pedit", array[m_pedit_options]]]
	m_police	nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["police", array[m_police_options]]]
	m_sample	nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["sample", array[m_sample_options]]]
	m_simple	nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["simple", array[m_simple_options]]]
	m_skbedit	nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["skbedit", array[m_skbedit_options]]]
	m_skbmod	nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["skbmod", array[m_skbmod_options]]]
	m_tunnel_key	nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["tunnel_key", array[m_tunnel_key_options]]]
	m_vlan		nlattr_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_t["vlan", array[m_vlan_options]]]
] [varlen]

type tca_actions_t[NAME, VALUES] {
	TCA_ACT_KIND	nlattr[TCA_ACT_KIND, string[NAME]]
	TCA_ACT_OPTIONS	nlattr[TCA_ACT_OPTIONS, VALUES]
	TCA_ACT_COOKIE	nlattr[TCA_ACT_COOKIE, array[int8]]
} [packed, align_4]

m_bpf_options [
	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]

m_connmark_options [
	TCA_CONNMARK_PARMS	nlattr[TCA_CONNMARK_PARMS, tc_connmark]
] [varlen]

m_csum_options [
	TCA_CSUM_PARMS	nlattr[TCA_CSUM_PARMS, tc_csum]
] [varlen]

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

m_ife_options [
	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]

#TODO: add TCA_IPT_TARG support
m_ipt_options [
	TCA_IPT_TABLE	nlattr[TCA_IPT_TABLE, string[ipt_tables, IFNAMSIZ]]
	TCA_IPT_HOOK	nlattr[TCA_IPT_HOOK, flags[nf_inet_hooks, int32]]
	TCA_IPT_INDEX	nlattr[TCA_IPT_INDEX, int32]
] [varlen]

m_mirred_options [
	TCA_MIRRED_PARMS	nlattr[TCA_MIRRED_PARMS, tc_mirred]
] [varlen]

m_nat_options [
	TCA_NAT_PARMS	nlattr[TCA_NAT_PARMS, tc_nat]
] [varlen]

m_pedit_options [
	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	nlattr[TCA_PEDIT_KEYS_EX, array[tca_pedit_keys_ex_policy]]
] [varlen]

tca_pedit_keys_ex_policy [
	TCA_PEDIT_KEY_EX	nlattr[TCA_PEDIT_KEY_EX, array[tca_pedit_key_ex_policy]]
] [varlen]

tca_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]

m_police_options [
	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]
] [varlen]

m_sample_options [
	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]

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

m_skbedit_options [
	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]

m_skbmod_options [
	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]

m_tunnel_key_options [
	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]

m_vlan_options [
	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_t[int32[0:TCA_ACT_MAX_PRIO], tca_actions_kind_index]]]
] [varlen]

tca_actions_kind_index [
	TCA_ACT_KIND	nlattr[TCA_ACT_KIND, string[tca_actions_kinds]]
	TCA_ACT_INDEX	nlattr[TCA_ACT_INDEX, int32]
] [varlen]

action_dump_flags [
	TCA_ROOT_FLAGS		nlattr[TCA_ROOT_FLAGS, nla_bitfield32]
	TCA_ROOT_TIME_DELTA	nlattr[TCA_ROOT_TIME_DELTA, int32]
] [varlen]

action_dump_policy [
	action_gd		action_gd_policy
	action_dump_flags	action_dump_flags
] [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
}

nla_bitfield32 {
	value		int32[0:1]
	selector	int32[0:1]
}

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_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 ------------------------------
tca_polices [
	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]
] [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 ------------------------------
tca_ematches [
	TCA_EMATCH_TREE_HDR	nlattr[TCA_EMATCH_TREE_HDR, tcf_ematch_tree_hdr]
	TCA_EMATCH_TREE_LIST	nlattr[TCA_EMATCH_TREE_LIST, tca_ematch_tree_list]
] [varlen]

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

tca_ematch_tree_list [
	TCF_EM_CONTAINER	nlattr_t[int32, tcf_ematch_hdr[TCF_EM_CONTAINER, array[int8]]]
	TCF_EM_CMP		nlattr_t[int32, tcf_ematch_hdr[TCF_EM_CMP, tcf_em_cmp]]
	TCF_EM_NBYTE		nlattr_t[int32, tcf_ematch_hdr[TCF_EM_NBYTE, tcf_em_nbyte]]
	TCF_EM_U32		nlattr_t[int32, tcf_ematch_hdr[TCF_EM_U32, tc_u32_key]]
	TCF_EM_META		nlattr_t[int32, tcf_ematch_hdr[TCF_EM_META, array[tcf_em_meta_policy]]]
	TCF_EM_CANID		nlattr_t[int32, tcf_ematch_hdr[TCF_EM_CANID, can_filter]]
	TCF_EM_IPSET		nlattr_t[int32, tcf_ematch_hdr[TCF_EM_IPSET, xt_set_info]]
	TCF_EM_IPT		nlattr_t[int32, tcf_ematch_hdr[TCF_EM_IPT, array[tcf_em_ipt_policy]]]
] [varlen]

type tcf_ematch_hdr[KIND, PAYLOAD] {
	matchid	int16
	kind	const[KIND, int16]
	flags	int16
	pad	int16
	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	int32
	len	int16:12[0:10]
	layer	flags[tcf_layers, int8:4]
# TODO: The payload data len should be equal to tcf_em_nbyte.len
	payload	array[int8, 0:10]
} [align_4]

tc_u32_key {
	mask	int32be
	val	int32be
	off	int32
	offmask	int32
}

tcf_em_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]

can_filter {
	can_id		int32
	can_mask	int32
}

tcf_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]
# TODO: stab data should be tc_sizespec.tsize * sizeof(__u16)
	TCA_STAB_DATA	nlattr[TCA_STAB_DATA, array[int16, 0:10]]
] [varlen]

tc_sizespec {
	cell_log	int8
	size_log	int8
	cell_align	int16
	overhead	int32
	linklayer	flags[linklayer, int32]
	mpu		int32
	mtu		int32
	tsize		int32[0:10]
}

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