使用python的pyroute2在tc clsact在入口(ingress)和出口(egress)处添加bpf程序
先上结论
使用parent参数来控制入口(ffff:fff2)或是出口(ffff:fff3)。
# add ingress clsact
ip.tc("add-filter", "bpf", idx, ":1", fd=fd, name="myprog",
parent="ffff:fff2", classid=1, direct_action=True)
# add egress clsact
ip.tc("add-filter", "bpf", idx, ":1", fd=fd, name="myprog",
parent="ffff:fff3", classid=1, direct_action=True)
前置知识
(这里做简要复述,主要还是要看这个参考资料)
tc基础—使用tc时的大概几个步骤:
- 创建队列规则qdisc。
- 创建类别class,并attach到qdisc
- 创建filter,并attach到qdisc。用于对流量分类,并将包分发至不同的class
- 可给filter加action,决定丢包、转发等动作
tc的direct-action模式是将classifier的分类功能和action的动作功能合二唯一的一个功能,简化了流程,提升了性能。
tc clsact是一种队列规则qdisc,可以在入口(ingress)和出口(egress)处以direct-action模式attach bpf程序。
背景 & 问题
使用bcc作为ebpf前端编程时,产生了如何在tc钩子处的入口和出口处添加bpf程序的疑问。
在bcc的examples里找到了一个在tc入口处丢弃所有包的例子,该例子中,这样在tc入口处加载bpf程序:
ip = pyroute2.IPRoute()
ipdb = pyroute2.IPDB(nl=ip)
idx = ipdb.interfaces[device].index
ip.tc("add", "clsact", idx)
ip.tc("add-filter", "bpf", idx, ":1", fd=fn.fd, name=fn.name,
parent="ffff:fff2", classid=1, direct_action=True)
看的人很疑惑,完全找不到关于入口/出口的关键字。
解决
pyroute2例程
去翻了pyroute2关于clsact的官方文档,里面有这样一段例程:
# BPF ingress/egress example using clsact qdisc:
# open_bpf_fd is outside the scope of pyroute2
#fd = open_bpf_fd()
eth0 = ip.get_links(ifname="eth0")[0]
ip.tc("add", "clsact", eth0)
# add ingress clsact
ip.tc("add-filter", "bpf", idx, ":1", fd=fd, name="myprog",
parent="ffff:fff2", classid=1, direct_action=True)
# add egress clsact
ip.tc("add-filter", "bpf", idx, ":1", fd=fd, name="myprog",
parent="ffff:fff3", classid=1, direct_action=True)
可以看到bcc的例程和pyroute2例程的公共点是入口处的程序都使用了ffff:fff2这个parent,另外pyroute2例程在出口处使用了ffff:fff3这个parent。
小实验
于是自己运行代码跑了一下小实验,想看下不同的parent会有什么影响。结果除了ffff:fff2和ffff:fff3外的所有parent都会报pr2modules.netlink.exceptions.NetlinkError: (2, 'No such file or directory')错误。证明ffff:fff2和ffff:fff3应该是某个特定的数字。
tc clsact相关linux源码
去翻阅了linux tc clsact的commit记录,找到了以下代码:
#define TC_H_UNSPEC (0U)
#define TC_H_ROOT (0xFFFFFFFFU)
#define TC_H_INGRESS (0xFFFFFFF1U)
+#define TC_H_CLSACT TC_H_INGRESS
+
+#define TC_H_MIN_INGRESS 0xFFF2U //ffff:fff2
+#define TC_H_MIN_EGRESS 0xFFF3U // ffff:fff3
这说明:ffff:fff2和ffff:fff3是tc clsact的ingress和egress两个class的ID,因此加filter时对应的parent要写它两。因此,也就不难理解上述各个例程中的写法。