Skip to content

Add helpers for Linux Traffic Control (TC) filter#209

Open
peilin-ye wants to merge 6 commits intoosandov:mainfrom
peilin-ye:helpers_tc_filter
Open

Add helpers for Linux Traffic Control (TC) filter#209
peilin-ye wants to merge 6 commits intoosandov:mainfrom
peilin-ye:helpers_tc_filter

Conversation

@peilin-ye
Copy link
Copy Markdown
Contributor

Hi all,

These are helpers for Linux TC filter (struct tcf_proto) and filter chain (struct tcf_chain) that I found useful when debugging TC issues. They are only supported since Linux v4.13 because several related data structures didn't exist before that.

The test is skipped if kernel is older than v4.13 commit 5bc1701881e3 ("net: sched: introduce multichain support for filters"), and depends on config CONFIG_NET_SCH_HTB and CONFIG_NET_CLS_U32. It uses the TCA_CHAIN Netlink message attribute, which pyroute2 doesn't fully support yet, which is why the test may look a bit over-complicated. I will add TCA_CHAIN support to pyroute2 and clean it up.

Thanks,
Peilin Ye

Add a helper, for_each_tcf_chain(), to iterate over all TC filter chains
on a block (struct tcf_block *).  As an example:

	>>> eth0 = netdev_get_by_name(prog, "eth0")
	>>> htb = qdisc_lookup(eth0, 0x1)
	>>> block = Object(prog, "struct htb_sched *", htb.privdata.address_).block
	>>> for chain in for_each_tcf_chain(block):
	...     print(chain.index)
	...
	0
	1
	2

This is only supported since Linux kernel commit 2190d1d0944f ("net:
sched: introduce helpers to work with filter chains") in v4.13.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
Add a helper, get_tcf_chain_by_index(), to get a TC filter chain from a
block given the chain index number.  As an example:

	>>> eth0 = netdev_get_by_name(prog, "eth0")
	>>> htb = qdisc_lookup(eth0, 0x1)
	>>> block = Object(prog, "struct htb_sched *", htb.privdata.address_).block
	>>> chain = get_tcf_chain_by_index(block, 0)
	>>> chain.filter_chain.ops.kind
	b'u32'

This is only supported since Linux kernel commit 5bc1701881e3 ("net:
sched: introduce multichain support for filters") in v4.13.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
Add a helper, for_each_tcf_proto(), to iterate over all TC filters
(struct tcf_proto *) on a filter chain.  As an example:

	>>> eth0 = netdev_get_by_name(prog, "eth0")
	>>> htb = qdisc_lookup(eth0, 0x1)
	>>> block = Object(prog, "struct htb_sched *", htb.privdata.address_).block
	>>> chain = get_tcf_chain_by_index(block, 0)
	>>> for filter in for for_each_tcf_proto(chain):
	...     print(filter.ops.kind)
	b'u32'
	b'matchall'
	b'flower'

This is only supported since Linux kernel commit 2190d1d0944f ("net:
sched: introduce helpers to work with filter chains") in v4.13.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
Add a helper, get_tcf_proto_by_prio(), to get a TC filter (struct
tcf_proto *) from a chain given the priority (preference) number.  As an
example:

	>>> eth0 = netdev_get_by_name(prog, "eth0")
	>>> htb = qdisc_lookup(eth0, 0x1)
	>>> block = Object(prog, "struct htb_sched *", htb.privdata.address_).block
	>>> chain = get_tcf_chain_by_index(block, 0)
	>>> u32 = get_tcf_proto_by_prio(chain, 10)
	>>> u32.ops.kind
	b'u32'

This is only supported since Linux kernel commit 2190d1d0944f ("net:
sched: introduce helpers to work with filter chains") in v4.13.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
Since we are planning to add more TestTc() tests, factor out common code
and shared variables (e.g. drgn Object for network namespace).

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
Add a TestTc() test, test_tcf_chain_and_tcf_proto(), for the following
helpers:

	for_each_tcf_chain()
	for_each_tcf_proto()
	get_tcf_chain_by_index()
	get_tcf_proto_by_prio()

It depends on Linux kernel CONFIG_NET_SCH_HTB and CONFIG_NET_CLS_U32
configs, and is skipped if kernel is older than v4.13 (commit 5bc1701881e3
("net: sched: introduce multichain support for filters")).

It depends on the TCA_CHAIN netlink message attribute, which pyroute2
does not support yet.  Use a customized class tcmsg for now.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
@peilin-ye
Copy link
Copy Markdown
Contributor Author

Fixed a nlmsg not found issue found by the rpm-build job.

Copy link
Copy Markdown
Owner

@osandov osandov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only gave this a quick look and had some questions about the kernel versions involved. I'll give it a more thorough review once that's cleared up. Thank you!

Comment thread drgn/helpers/linux/tc.py
Comment on lines +36 to +45
# Before Linux kernel commit 5bc1701881e3 ("net: sched: introduce
# multichain support for filters") (in v4.13), each block contained only
# one chain.
try:
chain_list = block.chain_list.address_of_()
except AttributeError:
# Before Linux kernel commit 2190d1d0944f ("net: sched: introduce
# helpers to work with filter chains") (in v4.13), struct tcf_chain
# didn't exist.
return block.chain
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like both of these commits went in during v4.13-rc1. I wouldn't bother checking for the intermediate state between those two commits; let's just assume that the kernel is an official tagged release, which I think will simplify this.

Comment thread drgn/helpers/linux/tc.py
"""
Iterate over all TC filter chains on a block.

This is only supported since Linux v4.13.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with TC at all, but looking at the commits you reference here, it looks like TC filter chains didn't exist at all before 4.13, is that correct? Maybe we can say something like "This is only supported since Linux v4.13, before which TC filter chains didn't exist.".

Comment thread drgn/helpers/linux/tc.py
Comment on lines +47 to +48
for chain in list_for_each_entry("struct tcf_chain", chain_list, "list"):
yield chain
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can simplify this to:

Suggested change
for chain in list_for_each_entry("struct tcf_chain", chain_list, "list"):
yield chain
return list_for_each_entry("struct tcf_chain", chain_list, "list")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants