summaryrefslogtreecommitdiffstats
path: root/dev/plug_qdisc/plug_qdisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'dev/plug_qdisc/plug_qdisc.c')
-rw-r--r--dev/plug_qdisc/plug_qdisc.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/dev/plug_qdisc/plug_qdisc.c b/dev/plug_qdisc/plug_qdisc.c
new file mode 100644
index 0000000..bc47f5d
--- /dev/null
+++ b/dev/plug_qdisc/plug_qdisc.c
@@ -0,0 +1,86 @@
+#include <inttypes.h>
+#include <netlink/cache.h>
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/qdisc.h>
+#include <netlink/cli/link.h>
+#include <netlink/route/qdisc/plug.h>
+
+/*
+ * XXX Please, first note that this code is not safe. XXX
+ * It was developed fast so that to reproduce a bug.
+ * You will certainly have to adapt it to your application.
+ * But at least it gives an idea about how to programmatically use plug
+ * queueing disciplines.
+ */
+
+static struct nl_sock *nl_sock;
+static struct nl_cache *link_cache;
+static struct rtnl_qdisc *qdisc;
+static struct rtnl_tc *tc;
+
+static int qdisc_init(void)
+{
+ nl_sock = nl_cli_alloc_socket();
+ nl_cli_connect(nl_sock, NETLINK_ROUTE);
+ link_cache = nl_cli_link_alloc_cache(nl_sock);
+ qdisc = nl_cli_qdisc_alloc();
+ tc = (struct rtnl_tc *)qdisc;
+
+ return 0;
+}
+
+/* Stop buffering and release all buffered and incoming 'qdisc'
+ * queueing discipline traffic.
+ */
+int plug_qdisc_release_indefinite_buffer(void)
+{
+ rtnl_qdisc_plug_release_indefinite(qdisc);
+ return rtnl_qdisc_add(nl_sock, qdisc, 0);
+}
+
+/* Start buffering incoming 'qdisc' queueing discipline traffic. */
+int plug_qdisc_plug_buffer(void)
+{
+ rtnl_qdisc_plug_buffer(qdisc);
+ return rtnl_qdisc_add(nl_sock, qdisc, 0);
+}
+
+/* Create a plug qdisc attached to 'device' network device with 'parent'
+ * as parent, with 'id' as ID and 'limit' as buffer size.
+ * This is equivalent to use nl-qdisc-add tool like that:
+ * $ nl-qdisc-add --dev=<device> --parent=<parent> --id=<id> plug --limit <limit>
+ * $ nl-qdisc-add --dev=<device> --parent=<parent> --id=<id> --update plug --release-indefinite
+ */
+int plug_qdisc_attach(char *device, char *parent, char *id, uint32_t limit)
+{
+ int ret;
+
+ if (!tc && qdisc_init() == -1)
+ return -1;
+
+ nl_cli_tc_parse_dev(tc, link_cache, device);
+ nl_cli_tc_parse_parent(tc, parent);
+ if (!rtnl_tc_get_ifindex(tc))
+ return -1;
+
+ if (!rtnl_tc_get_parent(tc))
+ return -1;
+ if (id)
+ nl_cli_tc_parse_handle(tc, id, 1);
+
+ rtnl_tc_set_kind(tc, "plug");
+ if (limit)
+ rtnl_qdisc_plug_set_limit(qdisc, limit);
+
+ ret = rtnl_qdisc_add(nl_sock, qdisc, NLM_F_CREATE);
+ if (ret < 0) {
+ fprintf(stderr, "Could add attach qdisc: %s\n", nl_geterror(ret));
+ return -1;
+ }
+ /* Release buffer. */
+ plug_qdisc_release_indefinite_buffer();
+
+ return 0;
+}
+