Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

peilin-ye
Copy link
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
@peilin-ye
Copy link
Contributor Author

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

Copy link
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 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
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.

"""
Iterate over all TC filter chains on a block.

This is only supported since Linux v4.13.
Copy link
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 on lines +47 to +48
for chain in list_for_each_entry("struct tcf_chain", chain_list, "list"):
yield chain
Copy link
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