#include #include #include #include #include #include #include /* * 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= --parent= --id= plug --limit * $ nl-qdisc-add --dev= --parent= --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; }