From 047916ed6d808eee3757e5e5462e7f31c06444bf Mon Sep 17 00:00:00 2001 From: Przemyslaw Czarnota Date: Tue, 29 May 2018 09:57:16 +0200 Subject: flower: add flower classifier test case Adds test case to libnl testing flower classifier --- Makefile.am | 3 + tests/test-flower-filter-with-actions.c | 328 ++++++++++++++++++++++++ 2 files changed, 331 insertions(+) create mode 100644 tests/test-flower-filter-with-actions.c --- a/Makefile.am +++ b/Makefile.am @@ -867,6 +867,7 @@ check_PROGRAMS += \ tests/test-loopback-up-down \ tests/test-socket-creation \ tests/test-u32-filter-with-actions \ + tests/test-flower-filter-with-actions \ $(NULL) tests_test_complex_HTB_with_hash_filters_CPPFLAGS = $(tests_cppflags) @@ -917,6 +918,8 @@ tests_test_socket_creation_CPPFLAGS tests_test_socket_creation_LDADD = $(tests_ldadd) tests_test_u32_filter_with_actions_CPPFLAGS = $(tests_cppflags) tests_test_u32_filter_with_actions_LDADD = $(tests_ldadd) +tests_test_flower_filter_with_actions_CPPFLAGS = $(tests_cppflags) +tests_test_flower_filter_with_actions_LDADD = $(tests_ldadd) check_PROGRAMS += \ tests/test-cache-mngr \ --- /dev/null +++ b/tests/test-flower-filter-with-actions.c @@ -0,0 +1,328 @@ +/* + * test/tests-flower-with-actions.c + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2018 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* + * function that adds a new ingress qdisc and set the default class for unclassified traffic + */ +static +int qdisc_add_ingress(struct nl_sock *sock, struct rtnl_link *rtnlLink) +{ + struct rtnl_qdisc *qdisc; + int err; + + /* Allocation of a qdisc object */ + qdisc = rtnl_qdisc_alloc(); + if (!qdisc) { + printf("Can not allocate Qdisc\n"); + return -1; + } + + rtnl_tc_set_link(TC_CAST(qdisc), rtnlLink); + rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT); + + rtnl_qdisc_delete(sock, qdisc); + + rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(0xffff, 0)); + + err = rtnl_tc_set_kind(TC_CAST(qdisc), "ingress"); + if (err) { + printf("Can not allocate ingress\n"); + return -1; + } + + /* Submit request to kernel and wait for response */ + err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE); + if (err) { + printf("Can not allocate ingress Qdisc\n"); + return -1; + } + + /* Return the qdisc object to free memory resources */ + rtnl_qdisc_put(qdisc); + + return 0; +} + +char *run_command(const char *cmd) +{ + char *output = NULL; + int output_size = 1; + char buffer[256] = { 0 }; + int size = 0; + void *tmp; + FILE *pipe = popen(cmd, "r"); + + if (!pipe) { + printf("Failed to open pipe\n"); + return NULL; + } + + while ((size = + fread(buffer, sizeof(*buffer), + sizeof(buffer) / sizeof(*buffer) - 1, pipe))) { + unsigned int string_len = strlen(buffer); + + tmp = realloc(output, output_size + string_len); + if (!tmp) + break; + + output = tmp; + memcpy(output + output_size - 1, buffer, string_len + 1); + output_size += string_len; + memset(buffer, 0, sizeof(buffer)); + } + + pclose(pipe); + + if (output == NULL) + return calloc(1, sizeof(char)); + + return output; +} + +static int run_test(void) +{ + char *output = NULL; + int ret = 0; + + output = run_command("tc -s -d filter show dev d0 ingress"); + + if (!strstr(output, "vlan_id 7")) { + printf("unexpected vlan_id\n"); + ret = -1; + goto err; + } + + if (!strstr(output, "vlan_prio 1")) { + printf("unexpected vlan_prio\n"); + ret = -1; + goto err; + } + + if (!strstr + (output, "filter parent ffff:fff1 protocol 802.1Q pref 1 flower handle 0x1")) { + printf("unexpected flower classifier\n"); + ret = -1; + goto err; + } + + if (!strstr(output, "indev")) { + printf("unexpected indev\n"); + ret = -1; + goto err; + } + +err: + if (ret) + printf(output); + else + printf("ok\n"); + + free(output); + return ret; +} + + +static int setup_flower_classifier(struct nl_sock *sock, + struct nl_cache *link_cache) +{ + struct rtnl_cls *cls; + struct rtnl_act *act; + int err = 0; + int ifindex; + + cls = rtnl_cls_alloc(); + if (!cls) { + printf("Unable to allocate classifier\n"); + err = -1; + goto err_classifier; + } + + err = rtnl_tc_set_kind(TC_CAST(cls), "flower"); + if (err) { + printf("Unable to set kind to flower classifier\n"); + goto err_classifier; + } + + rtnl_cls_set_prio(cls, 1); + rtnl_cls_set_protocol(cls, ETH_P_8021Q); + + err = nl_cache_refill(sock, link_cache); + if (err) { + printf("Unable to refill cache\n"); + goto err_cache; + } + + ifindex = rtnl_link_name2i(link_cache, "d0"); + if (!ifindex) { + printf("Unable to get link name\n"); + err = -1; + goto err_link_name; + } + + rtnl_tc_set_ifindex(TC_CAST(cls), ifindex); + rtnl_tc_set_handle(TC_CAST(cls), 1); + rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(0xffff, 0xfff1)); + err = rtnl_flower_set_indev(cls, "d0"); + if (err) { + printf("Unable to set indev\n"); + goto err_indev; + } + err = rtnl_flower_set_vlan_id(cls, 7); + if (err) { + printf("Unable to set vlan_id: %d\n", err); + goto err_vlan_id; + } + err = rtnl_flower_set_vlan_prio(cls, 1); + if (err) { + printf("Unable to set vlan_prio: %d\n", err); + goto err_vlan_prio; + } + + act = rtnl_act_alloc(); + if (!act) { + printf("Unable to allocate action\n"); + err = -1; + goto err_action; + } + + rtnl_tc_set_kind(TC_CAST(act), "gact"); + rtnl_gact_set_action(act, TC_ACT_OK); + + err = rtnl_flower_add_action(cls, act); + if (err) { + printf("Unable to add action"); + goto err_action_add; + } + + err = rtnl_cls_add(sock, cls, NLM_F_CREATE); + if (err) { + printf("Unable to create classifier: %d\n", err); + goto err_cls_add; + } + + err = run_test(); + if (err) { + printf("test case failed\n"); + } + + err = rtnl_cls_delete(sock, cls, 0); + if (err) { + printf("Unable to delete classifier: %d\n", err); + } + +err_cls_add: +err_action_add: + rtnl_act_put(act); +err_action: +err_vlan_prio: +err_vlan_id: +err_indev: +err_link_name: +err_cache: + rtnl_cls_put(cls); +err_classifier: + return err; +} + +int main(void) +{ + struct nl_sock *sock; + struct nl_cache *link_cache; + struct rtnl_link *dummy, *created; + int err = 0; + + sock = nl_socket_alloc(); + if (!sock) { + printf("Unable to allocate netlink socket\n"); + goto err_sock_alloc; + } + + err = nl_connect(sock, NETLINK_ROUTE); + if (err < 0) { + printf("Nu s-a putut conecta la NETLINK!\n"); + goto err_sock_alloc; + } + + err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache); + if (err < 0) { + printf("Unable to allocate link cache: %s\n", nl_geterror(err)); + goto err_alloc_cache; + } + + dummy = rtnl_link_alloc(); + if (!dummy) { + printf("Unable to allocate dummy link\n"); + err = -1; + goto err_link_alloc; + } + + err = rtnl_link_set_type(dummy, "dummy"); + if (err) { + printf("Unable to set link type to dummy\n"); + goto err_link_type; + } + + rtnl_link_set_name(dummy, "d0"); + + err = rtnl_link_add(sock, dummy, NLM_F_CREATE); + if (err) { + printf("Unable to add link\n"); + goto err_link_add; + } + + err = nl_cache_refill(sock, link_cache); + if (err) { + printf("Unable to fill cache\n"); + goto err_cache; + } + + created = rtnl_link_get_by_name(link_cache, "d0"); + if (!created) { + printf("Unable to get dummy interface\n"); + goto err_get_link; + } + qdisc_add_ingress(sock, created); + + err = setup_flower_classifier(sock, link_cache); + + rtnl_link_put(created); +err_get_link: +err_cache: + rtnl_link_delete(sock, dummy); +err_link_add: +err_link_type: + rtnl_link_put(dummy); +err_link_alloc: + nl_cache_free(link_cache); +err_alloc_cache: + nl_socket_free(sock); +err_sock_alloc: + return err; +}