Add support to attach / replace / detach clsact qdisc to libtcutils
Bug: 202086915
Bug: 157552970
Test: atest LibTcUtilsTest
Change-Id: I2f2e2f66acb7590e8951ac6e178c5893ba635597
diff --git a/staticlibs/native/tcutils/include/tcutils/tcutils.h b/staticlibs/native/tcutils/include/tcutils/tcutils.h
index d1e1bb7..0dbde34 100644
--- a/staticlibs/native/tcutils/include/tcutils/tcutils.h
+++ b/staticlibs/native/tcutils/include/tcutils/tcutils.h
@@ -17,10 +17,26 @@
#pragma once
#include <cstdint>
+#include <linux/rtnetlink.h>
namespace android {
int isEthernet(const char *iface, bool &isEthernet);
+
+int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags);
+
+static inline int tcAddQdiscClsact(int ifIndex) {
+ return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_EXCL | NLM_F_CREATE);
+}
+
+static inline int tcReplaceQdiscClsact(int ifIndex) {
+ return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_REPLACE);
+}
+
+static inline int tcDeleteQdiscClsact(int ifIndex) {
+ return doTcQdiscClsact(ifIndex, RTM_DELQDISC, 0);
+}
+
int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
const char *bpfProgPath);
int tcDeleteFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto);
diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp
index 3f24178..9b8c843 100644
--- a/staticlibs/native/tcutils/tcutils.cpp
+++ b/staticlibs/native/tcutils/tcutils.cpp
@@ -212,6 +212,54 @@
}
}
+// ADD: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_EXCL|NLM_F_CREATE
+// REPLACE: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_CREATE|NLM_F_REPLACE
+// DEL: nlMsgType=RTM_DELQDISC nlMsgFlags=0
+int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags) {
+ // This is the name of the qdisc we are attaching.
+ // Some hoop jumping to make this compile time constant with known size,
+ // so that the structure declaration is well defined at compile time.
+#define CLSACT "clsact"
+ // sizeof() includes the terminating NULL
+ static constexpr size_t ASCIIZ_LEN_CLSACT = sizeof(CLSACT);
+
+ const struct {
+ nlmsghdr n;
+ tcmsg t;
+ struct {
+ nlattr attr;
+ char str[NLMSG_ALIGN(ASCIIZ_LEN_CLSACT)];
+ } kind;
+ } req = {
+ .n =
+ {
+ .nlmsg_len = sizeof(req),
+ .nlmsg_type = nlMsgType,
+ .nlmsg_flags =
+ static_cast<__u16>(NETLINK_REQUEST_FLAGS | nlMsgFlags),
+ },
+ .t =
+ {
+ .tcm_family = AF_UNSPEC,
+ .tcm_ifindex = ifIndex,
+ .tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0),
+ .tcm_parent = TC_H_CLSACT,
+ },
+ .kind =
+ {
+ .attr =
+ {
+ .nla_len = NLA_HDRLEN + ASCIIZ_LEN_CLSACT,
+ .nla_type = TCA_KIND,
+ },
+ .str = CLSACT,
+ },
+ };
+#undef CLSACT
+
+ return sendAndProcessNetlinkResponse(&req, sizeof(req));
+}
+
// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned
// /sys/fs/bpf/... direct-action
int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp
index bab2d3e..6f28fbe 100644
--- a/staticlibs/native/tcutils/tests/tcutils_test.cpp
+++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp
@@ -63,4 +63,16 @@
ASSERT_FALSE(result);
}
+// See Linux kernel source in include/net/flow.h
+static constexpr int LOOPBACK_IFINDEX = 1;
+
+TEST(LibTcUtilsTest, AttachReplaceDetachClsactLo) {
+ // This attaches and detaches a configuration-less and thus no-op clsact
+ // qdisc to loopback interface (and it takes fractions of a second)
+ EXPECT_EQ(0, tcAddQdiscClsact(LOOPBACK_IFINDEX));
+ EXPECT_EQ(0, tcReplaceQdiscClsact(LOOPBACK_IFINDEX));
+ EXPECT_EQ(0, tcDeleteQdiscClsact(LOOPBACK_IFINDEX));
+ EXPECT_EQ(-EINVAL, tcDeleteQdiscClsact(LOOPBACK_IFINDEX));
+}
+
} // namespace android