Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'tools-ynl-convert-samples-into-selftests'

Jakub Kicinski says:

====================
tools: ynl: convert samples into selftests

The "samples" were always poor man's tests, used to manually
confirm that C YNL works as expected. Since a proper tests/
directory now exists move the samples and use the kselftest
harness to turn them into selftests outputting KTAP.
====================

Link: https://patch.msgid.link/20260307033630.1396085-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+1501 -1119
+2 -2
tools/net/ynl/Makefile
··· 14 14 15 15 SPECDIR=../../../Documentation/netlink/specs 16 16 17 - SUBDIRS = lib generated samples ynltool tests 17 + SUBDIRS = lib generated ynltool tests 18 18 19 19 all: $(SUBDIRS) libynl.a 20 20 21 + tests: | lib generated libynl.a 21 22 ynltool: | lib generated libynl.a 22 - samples: | lib generated 23 23 libynl.a: | lib generated 24 24 @echo -e "\tAR $@" 25 25 @ar rcs $@ lib/ynl.o generated/*-user.o
+1 -2
tools/net/ynl/samples/.gitignore tools/net/ynl/tests/.gitignore
··· 1 - ethtool 2 1 devlink 2 + ethtool 3 3 netdev 4 4 ovs 5 - page-pool 6 5 rt-addr 7 6 rt-link 8 7 rt-route
-36
tools/net/ynl/samples/Makefile
··· 1 - # SPDX-License-Identifier: GPL-2.0 2 - 3 - include ../Makefile.deps 4 - 5 - CC=gcc 6 - CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ 7 - -I../lib/ -I../generated/ -idirafter $(UAPI_PATH) 8 - ifeq ("$(DEBUG)","1") 9 - CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan 10 - endif 11 - 12 - LDLIBS=../lib/ynl.a ../generated/protos.a 13 - 14 - SRCS=$(wildcard *.c) 15 - BINS=$(patsubst %.c,%,${SRCS}) 16 - 17 - include $(wildcard *.d) 18 - 19 - all: $(BINS) 20 - 21 - CFLAGS_page-pool=$(CFLAGS_netdev) 22 - CFLAGS_tc-filter-add:=$(CFLAGS_tc) 23 - 24 - $(BINS): ../lib/ynl.a ../generated/protos.a $(SRCS) 25 - @echo -e '\tCC sample $@' 26 - @$(COMPILE.c) $(CFLAGS_$@) $@.c -o $@.o 27 - @$(LINK.c) $@.o -o $@ $(LDLIBS) 28 - 29 - clean: 30 - rm -f *.o *.d *~ 31 - 32 - distclean: clean 33 - rm -f $(BINS) 34 - 35 - .PHONY: all clean distclean 36 - .DEFAULT_GOAL=all
-61
tools/net/ynl/samples/devlink.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - 5 - #include <ynl.h> 6 - 7 - #include "devlink-user.h" 8 - 9 - int main(int argc, char **argv) 10 - { 11 - struct devlink_get_list *devs; 12 - struct ynl_sock *ys; 13 - 14 - ys = ynl_sock_create(&ynl_devlink_family, NULL); 15 - if (!ys) 16 - return 1; 17 - 18 - devs = devlink_get_dump(ys); 19 - if (!devs) 20 - goto err_close; 21 - 22 - ynl_dump_foreach(devs, d) { 23 - struct devlink_info_get_req *info_req; 24 - struct devlink_info_get_rsp *info_rsp; 25 - unsigned i; 26 - 27 - printf("%s/%s:\n", d->bus_name, d->dev_name); 28 - 29 - info_req = devlink_info_get_req_alloc(); 30 - devlink_info_get_req_set_bus_name(info_req, d->bus_name); 31 - devlink_info_get_req_set_dev_name(info_req, d->dev_name); 32 - 33 - info_rsp = devlink_info_get(ys, info_req); 34 - devlink_info_get_req_free(info_req); 35 - if (!info_rsp) 36 - goto err_free_devs; 37 - 38 - if (info_rsp->_len.info_driver_name) 39 - printf(" driver: %s\n", info_rsp->info_driver_name); 40 - if (info_rsp->_count.info_version_running) 41 - printf(" running fw:\n"); 42 - for (i = 0; i < info_rsp->_count.info_version_running; i++) 43 - printf(" %s: %s\n", 44 - info_rsp->info_version_running[i].info_version_name, 45 - info_rsp->info_version_running[i].info_version_value); 46 - printf(" ...\n"); 47 - devlink_info_get_rsp_free(info_rsp); 48 - } 49 - devlink_get_list_free(devs); 50 - 51 - ynl_sock_destroy(ys); 52 - 53 - return 0; 54 - 55 - err_free_devs: 56 - devlink_get_list_free(devs); 57 - err_close: 58 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 59 - ynl_sock_destroy(ys); 60 - return 2; 61 - }
-65
tools/net/ynl/samples/ethtool.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - 5 - #include <ynl.h> 6 - 7 - #include <net/if.h> 8 - 9 - #include "ethtool-user.h" 10 - 11 - int main(int argc, char **argv) 12 - { 13 - struct ethtool_channels_get_req_dump creq = {}; 14 - struct ethtool_rings_get_req_dump rreq = {}; 15 - struct ethtool_channels_get_list *channels; 16 - struct ethtool_rings_get_list *rings; 17 - struct ynl_sock *ys; 18 - 19 - ys = ynl_sock_create(&ynl_ethtool_family, NULL); 20 - if (!ys) 21 - return 1; 22 - 23 - creq._present.header = 1; /* ethtool needs an empty nest, sigh */ 24 - channels = ethtool_channels_get_dump(ys, &creq); 25 - if (!channels) 26 - goto err_close; 27 - 28 - printf("Channels:\n"); 29 - ynl_dump_foreach(channels, dev) { 30 - printf(" %8s: ", dev->header.dev_name); 31 - if (dev->_present.rx_count) 32 - printf("rx %d ", dev->rx_count); 33 - if (dev->_present.tx_count) 34 - printf("tx %d ", dev->tx_count); 35 - if (dev->_present.combined_count) 36 - printf("combined %d ", dev->combined_count); 37 - printf("\n"); 38 - } 39 - ethtool_channels_get_list_free(channels); 40 - 41 - rreq._present.header = 1; /* ethtool needs an empty nest.. */ 42 - rings = ethtool_rings_get_dump(ys, &rreq); 43 - if (!rings) 44 - goto err_close; 45 - 46 - printf("Rings:\n"); 47 - ynl_dump_foreach(rings, dev) { 48 - printf(" %8s: ", dev->header.dev_name); 49 - if (dev->_present.rx) 50 - printf("rx %d ", dev->rx); 51 - if (dev->_present.tx) 52 - printf("tx %d ", dev->tx); 53 - printf("\n"); 54 - } 55 - ethtool_rings_get_list_free(rings); 56 - 57 - ynl_sock_destroy(ys); 58 - 59 - return 0; 60 - 61 - err_close: 62 - fprintf(stderr, "YNL (%d): %s\n", ys->err.code, ys->err.msg); 63 - ynl_sock_destroy(ys); 64 - return 2; 65 - }
-128
tools/net/ynl/samples/netdev.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - 5 - #include <ynl.h> 6 - 7 - #include <net/if.h> 8 - 9 - #include "netdev-user.h" 10 - 11 - /* netdev genetlink family code sample 12 - * This sample shows off basics of the netdev family but also notification 13 - * handling, hence the somewhat odd UI. We subscribe to notifications first 14 - * then wait for ifc selection, so the socket may already accumulate 15 - * notifications as we wait. This allows us to test that YNL can handle 16 - * requests and notifications getting interleaved. 17 - */ 18 - 19 - static void netdev_print_device(struct netdev_dev_get_rsp *d, unsigned int op) 20 - { 21 - char ifname[IF_NAMESIZE]; 22 - const char *name; 23 - 24 - if (!d->_present.ifindex) 25 - return; 26 - 27 - name = if_indextoname(d->ifindex, ifname); 28 - if (name) 29 - printf("%8s", name); 30 - printf("[%d]\t", d->ifindex); 31 - 32 - if (!d->_present.xdp_features) 33 - return; 34 - 35 - printf("xdp-features (%llx):", d->xdp_features); 36 - for (int i = 0; d->xdp_features >= 1U << i; i++) { 37 - if (d->xdp_features & (1U << i)) 38 - printf(" %s", netdev_xdp_act_str(1 << i)); 39 - } 40 - 41 - printf(" xdp-rx-metadata-features (%llx):", d->xdp_rx_metadata_features); 42 - for (int i = 0; d->xdp_rx_metadata_features >= 1U << i; i++) { 43 - if (d->xdp_rx_metadata_features & (1U << i)) 44 - printf(" %s", netdev_xdp_rx_metadata_str(1 << i)); 45 - } 46 - 47 - printf(" xsk-features (%llx):", d->xsk_features); 48 - for (int i = 0; d->xsk_features >= 1U << i; i++) { 49 - if (d->xsk_features & (1U << i)) 50 - printf(" %s", netdev_xsk_flags_str(1 << i)); 51 - } 52 - 53 - printf(" xdp-zc-max-segs=%u", d->xdp_zc_max_segs); 54 - 55 - name = netdev_op_str(op); 56 - if (name) 57 - printf(" (ntf: %s)", name); 58 - printf("\n"); 59 - } 60 - 61 - int main(int argc, char **argv) 62 - { 63 - struct netdev_dev_get_list *devs; 64 - struct ynl_ntf_base_type *ntf; 65 - struct ynl_error yerr; 66 - struct ynl_sock *ys; 67 - int ifindex = 0; 68 - 69 - if (argc > 1) 70 - ifindex = strtol(argv[1], NULL, 0); 71 - 72 - ys = ynl_sock_create(&ynl_netdev_family, &yerr); 73 - if (!ys) { 74 - fprintf(stderr, "YNL: %s\n", yerr.msg); 75 - return 1; 76 - } 77 - 78 - if (ynl_subscribe(ys, "mgmt")) 79 - goto err_close; 80 - 81 - printf("Select ifc ($ifindex; or 0 = dump; or -2 ntf check): "); 82 - if (scanf("%d", &ifindex) != 1) { 83 - fprintf(stderr, "Error: unable to parse input\n"); 84 - goto err_destroy; 85 - } 86 - 87 - if (ifindex > 0) { 88 - struct netdev_dev_get_req *req; 89 - struct netdev_dev_get_rsp *d; 90 - 91 - req = netdev_dev_get_req_alloc(); 92 - netdev_dev_get_req_set_ifindex(req, ifindex); 93 - 94 - d = netdev_dev_get(ys, req); 95 - netdev_dev_get_req_free(req); 96 - if (!d) 97 - goto err_close; 98 - 99 - netdev_print_device(d, 0); 100 - netdev_dev_get_rsp_free(d); 101 - } else if (!ifindex) { 102 - devs = netdev_dev_get_dump(ys); 103 - if (!devs) 104 - goto err_close; 105 - 106 - if (ynl_dump_empty(devs)) 107 - fprintf(stderr, "Error: no devices reported\n"); 108 - ynl_dump_foreach(devs, d) 109 - netdev_print_device(d, 0); 110 - netdev_dev_get_list_free(devs); 111 - } else if (ifindex == -2) { 112 - ynl_ntf_check(ys); 113 - } 114 - while ((ntf = ynl_ntf_dequeue(ys))) { 115 - netdev_print_device((struct netdev_dev_get_rsp *)&ntf->data, 116 - ntf->cmd); 117 - ynl_ntf_free(ntf); 118 - } 119 - 120 - ynl_sock_destroy(ys); 121 - return 0; 122 - 123 - err_close: 124 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 125 - err_destroy: 126 - ynl_sock_destroy(ys); 127 - return 2; 128 - }
-60
tools/net/ynl/samples/ovs.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - 5 - #include <ynl.h> 6 - 7 - #include "ovs_datapath-user.h" 8 - 9 - int main(int argc, char **argv) 10 - { 11 - struct ynl_sock *ys; 12 - int err; 13 - 14 - ys = ynl_sock_create(&ynl_ovs_datapath_family, NULL); 15 - if (!ys) 16 - return 1; 17 - 18 - if (argc > 1) { 19 - struct ovs_datapath_new_req *req; 20 - 21 - req = ovs_datapath_new_req_alloc(); 22 - if (!req) 23 - goto err_close; 24 - 25 - ovs_datapath_new_req_set_upcall_pid(req, 1); 26 - ovs_datapath_new_req_set_name(req, argv[1]); 27 - 28 - err = ovs_datapath_new(ys, req); 29 - ovs_datapath_new_req_free(req); 30 - if (err) 31 - goto err_close; 32 - } else { 33 - struct ovs_datapath_get_req_dump *req; 34 - struct ovs_datapath_get_list *dps; 35 - 36 - printf("Dump:\n"); 37 - req = ovs_datapath_get_req_dump_alloc(); 38 - 39 - dps = ovs_datapath_get_dump(ys, req); 40 - ovs_datapath_get_req_dump_free(req); 41 - if (!dps) 42 - goto err_close; 43 - 44 - ynl_dump_foreach(dps, dp) { 45 - printf(" %s(%d): pid:%u cache:%u\n", 46 - dp->name, dp->_hdr.dp_ifindex, 47 - dp->upcall_pid, dp->masks_cache_size); 48 - } 49 - ovs_datapath_get_list_free(dps); 50 - } 51 - 52 - ynl_sock_destroy(ys); 53 - 54 - return 0; 55 - 56 - err_close: 57 - fprintf(stderr, "YNL (%d): %s\n", ys->err.code, ys->err.msg); 58 - ynl_sock_destroy(ys); 59 - return 2; 60 - }
-80
tools/net/ynl/samples/rt-addr.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - 5 - #include <ynl.h> 6 - 7 - #include <arpa/inet.h> 8 - #include <net/if.h> 9 - 10 - #include "rt-addr-user.h" 11 - 12 - static void rt_addr_print(struct rt_addr_getaddr_rsp *a) 13 - { 14 - char ifname[IF_NAMESIZE]; 15 - char addr_str[64]; 16 - const char *addr; 17 - const char *name; 18 - 19 - name = if_indextoname(a->_hdr.ifa_index, ifname); 20 - if (name) 21 - printf("%16s: ", name); 22 - 23 - switch (a->_len.address) { 24 - case 4: 25 - addr = inet_ntop(AF_INET, a->address, 26 - addr_str, sizeof(addr_str)); 27 - break; 28 - case 16: 29 - addr = inet_ntop(AF_INET6, a->address, 30 - addr_str, sizeof(addr_str)); 31 - break; 32 - default: 33 - addr = NULL; 34 - break; 35 - } 36 - if (addr) 37 - printf("%s", addr); 38 - else 39 - printf("[%d]", a->_len.address); 40 - 41 - printf("\n"); 42 - } 43 - 44 - int main(int argc, char **argv) 45 - { 46 - struct rt_addr_getaddr_list *rsp; 47 - struct rt_addr_getaddr_req *req; 48 - struct ynl_error yerr; 49 - struct ynl_sock *ys; 50 - 51 - ys = ynl_sock_create(&ynl_rt_addr_family, &yerr); 52 - if (!ys) { 53 - fprintf(stderr, "YNL: %s\n", yerr.msg); 54 - return 1; 55 - } 56 - 57 - req = rt_addr_getaddr_req_alloc(); 58 - if (!req) 59 - goto err_destroy; 60 - 61 - rsp = rt_addr_getaddr_dump(ys, req); 62 - rt_addr_getaddr_req_free(req); 63 - if (!rsp) 64 - goto err_close; 65 - 66 - if (ynl_dump_empty(rsp)) 67 - fprintf(stderr, "Error: no addresses reported\n"); 68 - ynl_dump_foreach(rsp, addr) 69 - rt_addr_print(addr); 70 - rt_addr_getaddr_list_free(rsp); 71 - 72 - ynl_sock_destroy(ys); 73 - return 0; 74 - 75 - err_close: 76 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 77 - err_destroy: 78 - ynl_sock_destroy(ys); 79 - return 2; 80 - }
-184
tools/net/ynl/samples/rt-link.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - 5 - #include <ynl.h> 6 - 7 - #include <arpa/inet.h> 8 - #include <net/if.h> 9 - 10 - #include "rt-link-user.h" 11 - 12 - static void rt_link_print(struct rt_link_getlink_rsp *r) 13 - { 14 - unsigned int i; 15 - 16 - printf("%3d: ", r->_hdr.ifi_index); 17 - 18 - if (r->_len.ifname) 19 - printf("%16s: ", r->ifname); 20 - 21 - if (r->_present.mtu) 22 - printf("mtu %5d ", r->mtu); 23 - 24 - if (r->linkinfo._len.kind) 25 - printf("kind %-8s ", r->linkinfo.kind); 26 - else 27 - printf(" %8s ", ""); 28 - 29 - if (r->prop_list._count.alt_ifname) { 30 - printf("altname "); 31 - for (i = 0; i < r->prop_list._count.alt_ifname; i++) 32 - printf("%s ", r->prop_list.alt_ifname[i]->str); 33 - printf(" "); 34 - } 35 - 36 - if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) { 37 - struct rt_link_linkinfo_netkit_attrs *netkit; 38 - const char *name; 39 - 40 - netkit = &r->linkinfo.data.netkit; 41 - printf("primary %d ", netkit->primary); 42 - 43 - name = NULL; 44 - if (netkit->_present.policy) 45 - name = rt_link_netkit_policy_str(netkit->policy); 46 - if (name) 47 - printf("policy %s ", name); 48 - } 49 - 50 - printf("\n"); 51 - } 52 - 53 - static int rt_link_create_netkit(struct ynl_sock *ys) 54 - { 55 - struct rt_link_getlink_ntf *ntf_gl; 56 - struct rt_link_newlink_req *req; 57 - struct ynl_ntf_base_type *ntf; 58 - int ret; 59 - 60 - req = rt_link_newlink_req_alloc(); 61 - if (!req) { 62 - fprintf(stderr, "Can't alloc req\n"); 63 - return -1; 64 - } 65 - 66 - /* rtnetlink doesn't provide info about the created object. 67 - * It expects us to set the ECHO flag and the dig the info out 68 - * of the notifications... 69 - */ 70 - rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); 71 - 72 - rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); 73 - 74 - /* Test error messages */ 75 - rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10); 76 - ret = rt_link_newlink(ys, req); 77 - if (ret) { 78 - printf("Testing error message for policy being bad:\n\t%s\n", ys->err.msg); 79 - } else { 80 - fprintf(stderr, "Warning: unexpected success creating netkit with bad attrs\n"); 81 - goto created; 82 - } 83 - 84 - rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP); 85 - 86 - ret = rt_link_newlink(ys, req); 87 - created: 88 - rt_link_newlink_req_free(req); 89 - if (ret) { 90 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 91 - return -1; 92 - } 93 - 94 - if (!ynl_has_ntf(ys)) { 95 - fprintf(stderr, 96 - "Warning: interface created but received no notification, won't delete the interface\n"); 97 - return 0; 98 - } 99 - 100 - ntf = ynl_ntf_dequeue(ys); 101 - if (ntf->cmd != RTM_NEWLINK) { 102 - fprintf(stderr, 103 - "Warning: unexpected notification type, won't delete the interface\n"); 104 - return 0; 105 - } 106 - ntf_gl = (void *)ntf; 107 - ret = ntf_gl->obj._hdr.ifi_index; 108 - ynl_ntf_free(ntf); 109 - 110 - return ret; 111 - } 112 - 113 - static void rt_link_del(struct ynl_sock *ys, int ifindex) 114 - { 115 - struct rt_link_dellink_req *req; 116 - 117 - req = rt_link_dellink_req_alloc(); 118 - if (!req) { 119 - fprintf(stderr, "Can't alloc req\n"); 120 - return; 121 - } 122 - 123 - req->_hdr.ifi_index = ifindex; 124 - if (rt_link_dellink(ys, req)) 125 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 126 - else 127 - fprintf(stderr, 128 - "Trying to delete a Netkit interface (ifindex %d)\n", 129 - ifindex); 130 - 131 - rt_link_dellink_req_free(req); 132 - } 133 - 134 - int main(int argc, char **argv) 135 - { 136 - struct rt_link_getlink_req_dump *req; 137 - struct rt_link_getlink_list *rsp; 138 - struct ynl_error yerr; 139 - struct ynl_sock *ys; 140 - int created = 0; 141 - 142 - ys = ynl_sock_create(&ynl_rt_link_family, &yerr); 143 - if (!ys) { 144 - fprintf(stderr, "YNL: %s\n", yerr.msg); 145 - return 1; 146 - } 147 - 148 - if (argc > 1) { 149 - fprintf(stderr, "Trying to create a Netkit interface\n"); 150 - created = rt_link_create_netkit(ys); 151 - if (created < 0) 152 - goto err_destroy; 153 - } 154 - 155 - req = rt_link_getlink_req_dump_alloc(); 156 - if (!req) 157 - goto err_del_ifc; 158 - 159 - rsp = rt_link_getlink_dump(ys, req); 160 - rt_link_getlink_req_dump_free(req); 161 - if (!rsp) 162 - goto err_close; 163 - 164 - if (ynl_dump_empty(rsp)) 165 - fprintf(stderr, "Error: no links reported\n"); 166 - ynl_dump_foreach(rsp, link) 167 - rt_link_print(link); 168 - rt_link_getlink_list_free(rsp); 169 - 170 - if (created) 171 - rt_link_del(ys, created); 172 - 173 - ynl_sock_destroy(ys); 174 - return 0; 175 - 176 - err_close: 177 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 178 - err_del_ifc: 179 - if (created) 180 - rt_link_del(ys, created); 181 - err_destroy: 182 - ynl_sock_destroy(ys); 183 - return 2; 184 - }
-80
tools/net/ynl/samples/rt-route.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - 5 - #include <ynl.h> 6 - 7 - #include <arpa/inet.h> 8 - #include <net/if.h> 9 - 10 - #include "rt-route-user.h" 11 - 12 - static void rt_route_print(struct rt_route_getroute_rsp *r) 13 - { 14 - char ifname[IF_NAMESIZE]; 15 - char route_str[64]; 16 - const char *route; 17 - const char *name; 18 - 19 - /* Ignore local */ 20 - if (r->_hdr.rtm_table == RT_TABLE_LOCAL) 21 - return; 22 - 23 - if (r->_present.oif) { 24 - name = if_indextoname(r->oif, ifname); 25 - if (name) 26 - printf("oif: %-16s ", name); 27 - } 28 - 29 - if (r->_len.dst) { 30 - route = inet_ntop(r->_hdr.rtm_family, r->dst, 31 - route_str, sizeof(route_str)); 32 - printf("dst: %s/%d", route, r->_hdr.rtm_dst_len); 33 - } 34 - 35 - if (r->_len.gateway) { 36 - route = inet_ntop(r->_hdr.rtm_family, r->gateway, 37 - route_str, sizeof(route_str)); 38 - printf("gateway: %s ", route); 39 - } 40 - 41 - printf("\n"); 42 - } 43 - 44 - int main(int argc, char **argv) 45 - { 46 - struct rt_route_getroute_req_dump *req; 47 - struct rt_route_getroute_list *rsp; 48 - struct ynl_error yerr; 49 - struct ynl_sock *ys; 50 - 51 - ys = ynl_sock_create(&ynl_rt_route_family, &yerr); 52 - if (!ys) { 53 - fprintf(stderr, "YNL: %s\n", yerr.msg); 54 - return 1; 55 - } 56 - 57 - req = rt_route_getroute_req_dump_alloc(); 58 - if (!req) 59 - goto err_destroy; 60 - 61 - rsp = rt_route_getroute_dump(ys, req); 62 - rt_route_getroute_req_dump_free(req); 63 - if (!rsp) 64 - goto err_close; 65 - 66 - if (ynl_dump_empty(rsp)) 67 - fprintf(stderr, "Error: no routeesses reported\n"); 68 - ynl_dump_foreach(rsp, route) 69 - rt_route_print(route); 70 - rt_route_getroute_list_free(rsp); 71 - 72 - ynl_sock_destroy(ys); 73 - return 0; 74 - 75 - err_close: 76 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 77 - err_destroy: 78 - ynl_sock_destroy(ys); 79 - return 2; 80 - }
-335
tools/net/ynl/samples/tc-filter-add.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - #include <stdlib.h> 5 - #include <arpa/inet.h> 6 - #include <linux/pkt_sched.h> 7 - #include <linux/tc_act/tc_vlan.h> 8 - #include <linux/tc_act/tc_gact.h> 9 - #include <linux/if_ether.h> 10 - #include <net/if.h> 11 - 12 - #include <ynl.h> 13 - 14 - #include "tc-user.h" 15 - 16 - #define TC_HANDLE (0xFFFF << 16) 17 - 18 - const char *vlan_act_name(struct tc_vlan *p) 19 - { 20 - switch (p->v_action) { 21 - case TCA_VLAN_ACT_POP: 22 - return "pop"; 23 - case TCA_VLAN_ACT_PUSH: 24 - return "push"; 25 - case TCA_VLAN_ACT_MODIFY: 26 - return "modify"; 27 - default: 28 - break; 29 - } 30 - 31 - return "not supported"; 32 - } 33 - 34 - const char *gact_act_name(struct tc_gact *p) 35 - { 36 - switch (p->action) { 37 - case TC_ACT_SHOT: 38 - return "drop"; 39 - case TC_ACT_OK: 40 - return "ok"; 41 - case TC_ACT_PIPE: 42 - return "pipe"; 43 - default: 44 - break; 45 - } 46 - 47 - return "not supported"; 48 - } 49 - 50 - static void print_vlan(struct tc_act_vlan_attrs *vlan) 51 - { 52 - printf("%s ", vlan_act_name(vlan->parms)); 53 - if (vlan->_present.push_vlan_id) 54 - printf("id %u ", vlan->push_vlan_id); 55 - if (vlan->_present.push_vlan_protocol) 56 - printf("protocol %#x ", ntohs(vlan->push_vlan_protocol)); 57 - if (vlan->_present.push_vlan_priority) 58 - printf("priority %u ", vlan->push_vlan_priority); 59 - } 60 - 61 - static void print_gact(struct tc_act_gact_attrs *gact) 62 - { 63 - struct tc_gact *p = gact->parms; 64 - 65 - printf("%s ", gact_act_name(p)); 66 - } 67 - 68 - static void flower_print(struct tc_flower_attrs *flower, const char *kind) 69 - { 70 - struct tc_act_attrs *a; 71 - unsigned int i; 72 - 73 - printf("%s:\n", kind); 74 - 75 - if (flower->_present.key_vlan_id) 76 - printf(" vlan_id: %u\n", flower->key_vlan_id); 77 - if (flower->_present.key_vlan_prio) 78 - printf(" vlan_prio: %u\n", flower->key_vlan_prio); 79 - if (flower->_present.key_num_of_vlans) 80 - printf(" num_of_vlans: %u\n", flower->key_num_of_vlans); 81 - 82 - for (i = 0; i < flower->_count.act; i++) { 83 - a = &flower->act[i]; 84 - printf("action order: %i %s ", i + 1, a->kind); 85 - if (a->options._present.vlan) 86 - print_vlan(&a->options.vlan); 87 - else if (a->options._present.gact) 88 - print_gact(&a->options.gact); 89 - printf("\n"); 90 - } 91 - printf("\n"); 92 - } 93 - 94 - static void tc_filter_print(struct tc_gettfilter_rsp *f) 95 - { 96 - struct tc_options_msg *opt = &f->options; 97 - 98 - if (opt->_present.flower) 99 - flower_print(&opt->flower, f->kind); 100 - else if (f->_len.kind) 101 - printf("%s pref %u proto: %#x\n", f->kind, 102 - (f->_hdr.tcm_info >> 16), 103 - ntohs(TC_H_MIN(f->_hdr.tcm_info))); 104 - } 105 - 106 - static int tc_filter_add(struct ynl_sock *ys, int ifi) 107 - { 108 - struct tc_newtfilter_req *req; 109 - struct tc_act_attrs *acts; 110 - struct tc_vlan p = { 111 - .action = TC_ACT_PIPE, 112 - .v_action = TCA_VLAN_ACT_PUSH 113 - }; 114 - __u16 flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE; 115 - int ret; 116 - 117 - req = tc_newtfilter_req_alloc(); 118 - if (!req) { 119 - fprintf(stderr, "tc_newtfilter_req_alloc failed\n"); 120 - return -1; 121 - } 122 - memset(req, 0, sizeof(*req)); 123 - 124 - acts = tc_act_attrs_alloc(3); 125 - if (!acts) { 126 - fprintf(stderr, "tc_act_attrs_alloc\n"); 127 - tc_newtfilter_req_free(req); 128 - return -1; 129 - } 130 - memset(acts, 0, sizeof(*acts) * 3); 131 - 132 - req->_hdr.tcm_ifindex = ifi; 133 - req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 134 - req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q)); 135 - req->chain = 0; 136 - 137 - tc_newtfilter_req_set_nlflags(req, flags); 138 - tc_newtfilter_req_set_kind(req, "flower"); 139 - tc_newtfilter_req_set_options_flower_key_vlan_id(req, 100); 140 - tc_newtfilter_req_set_options_flower_key_vlan_prio(req, 5); 141 - tc_newtfilter_req_set_options_flower_key_num_of_vlans(req, 3); 142 - 143 - __tc_newtfilter_req_set_options_flower_act(req, acts, 3); 144 - 145 - /* Skip action at index 0 because in TC, the action array 146 - * index starts at 1, with each index defining the action's 147 - * order. In contrast, in YNL indexed arrays start at index 0. 148 - */ 149 - tc_act_attrs_set_kind(&acts[1], "vlan"); 150 - tc_act_attrs_set_options_vlan_parms(&acts[1], &p, sizeof(p)); 151 - tc_act_attrs_set_options_vlan_push_vlan_id(&acts[1], 200); 152 - tc_act_attrs_set_kind(&acts[2], "vlan"); 153 - tc_act_attrs_set_options_vlan_parms(&acts[2], &p, sizeof(p)); 154 - tc_act_attrs_set_options_vlan_push_vlan_id(&acts[2], 300); 155 - 156 - tc_newtfilter_req_set_options_flower_flags(req, 0); 157 - tc_newtfilter_req_set_options_flower_key_eth_type(req, htons(0x8100)); 158 - 159 - ret = tc_newtfilter(ys, req); 160 - if (ret) 161 - fprintf(stderr, "tc_newtfilter: %s\n", ys->err.msg); 162 - 163 - tc_newtfilter_req_free(req); 164 - 165 - return ret; 166 - } 167 - 168 - static int tc_filter_show(struct ynl_sock *ys, int ifi) 169 - { 170 - struct tc_gettfilter_req_dump *req; 171 - struct tc_gettfilter_list *rsp; 172 - 173 - req = tc_gettfilter_req_dump_alloc(); 174 - if (!req) { 175 - fprintf(stderr, "tc_gettfilter_req_dump_alloc failed\n"); 176 - return -1; 177 - } 178 - memset(req, 0, sizeof(*req)); 179 - 180 - req->_hdr.tcm_ifindex = ifi; 181 - req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 182 - req->_present.chain = 1; 183 - req->chain = 0; 184 - 185 - rsp = tc_gettfilter_dump(ys, req); 186 - tc_gettfilter_req_dump_free(req); 187 - if (!rsp) { 188 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 189 - return -1; 190 - } 191 - 192 - if (ynl_dump_empty(rsp)) 193 - fprintf(stderr, "Error: no filters reported\n"); 194 - else 195 - ynl_dump_foreach(rsp, flt) tc_filter_print(flt); 196 - 197 - tc_gettfilter_list_free(rsp); 198 - 199 - return 0; 200 - } 201 - 202 - static int tc_filter_del(struct ynl_sock *ys, int ifi) 203 - { 204 - struct tc_deltfilter_req *req; 205 - __u16 flags = NLM_F_REQUEST; 206 - int ret; 207 - 208 - req = tc_deltfilter_req_alloc(); 209 - if (!req) { 210 - fprintf(stderr, "tc_deltfilter_req_alloc failed\n"); 211 - return -1; 212 - } 213 - memset(req, 0, sizeof(*req)); 214 - 215 - req->_hdr.tcm_ifindex = ifi; 216 - req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 217 - req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q)); 218 - tc_deltfilter_req_set_nlflags(req, flags); 219 - 220 - ret = tc_deltfilter(ys, req); 221 - if (ret) 222 - fprintf(stderr, "tc_deltfilter failed: %s\n", ys->err.msg); 223 - 224 - tc_deltfilter_req_free(req); 225 - 226 - return ret; 227 - } 228 - 229 - static int tc_clsact_add(struct ynl_sock *ys, int ifi) 230 - { 231 - struct tc_newqdisc_req *req; 232 - __u16 flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE; 233 - int ret; 234 - 235 - req = tc_newqdisc_req_alloc(); 236 - if (!req) { 237 - fprintf(stderr, "tc_newqdisc_req_alloc failed\n"); 238 - return -1; 239 - } 240 - memset(req, 0, sizeof(*req)); 241 - 242 - req->_hdr.tcm_ifindex = ifi; 243 - req->_hdr.tcm_parent = TC_H_CLSACT; 244 - req->_hdr.tcm_handle = TC_HANDLE; 245 - tc_newqdisc_req_set_nlflags(req, flags); 246 - tc_newqdisc_req_set_kind(req, "clsact"); 247 - 248 - ret = tc_newqdisc(ys, req); 249 - if (ret) 250 - fprintf(stderr, "tc_newqdisc failed: %s\n", ys->err.msg); 251 - 252 - tc_newqdisc_req_free(req); 253 - 254 - return ret; 255 - } 256 - 257 - static int tc_clsact_del(struct ynl_sock *ys, int ifi) 258 - { 259 - struct tc_delqdisc_req *req; 260 - __u16 flags = NLM_F_REQUEST; 261 - int ret; 262 - 263 - req = tc_delqdisc_req_alloc(); 264 - if (!req) { 265 - fprintf(stderr, "tc_delqdisc_req_alloc failed\n"); 266 - return -1; 267 - } 268 - memset(req, 0, sizeof(*req)); 269 - 270 - req->_hdr.tcm_ifindex = ifi; 271 - req->_hdr.tcm_parent = TC_H_CLSACT; 272 - req->_hdr.tcm_handle = TC_HANDLE; 273 - tc_delqdisc_req_set_nlflags(req, flags); 274 - 275 - ret = tc_delqdisc(ys, req); 276 - if (ret) 277 - fprintf(stderr, "tc_delqdisc failed: %s\n", ys->err.msg); 278 - 279 - tc_delqdisc_req_free(req); 280 - 281 - return ret; 282 - } 283 - 284 - static int tc_filter_config(struct ynl_sock *ys, int ifi) 285 - { 286 - int ret = 0; 287 - 288 - if (tc_filter_add(ys, ifi)) 289 - return -1; 290 - 291 - ret = tc_filter_show(ys, ifi); 292 - 293 - if (tc_filter_del(ys, ifi)) 294 - return -1; 295 - 296 - return ret; 297 - } 298 - 299 - int main(int argc, char **argv) 300 - { 301 - struct ynl_error yerr; 302 - struct ynl_sock *ys; 303 - int ifi, ret = 0; 304 - 305 - if (argc < 2) { 306 - fprintf(stderr, "Usage: %s <interface_name>\n", argv[0]); 307 - return 1; 308 - } 309 - ifi = if_nametoindex(argv[1]); 310 - if (!ifi) { 311 - perror("if_nametoindex"); 312 - return 1; 313 - } 314 - 315 - ys = ynl_sock_create(&ynl_tc_family, &yerr); 316 - if (!ys) { 317 - fprintf(stderr, "YNL: %s\n", yerr.msg); 318 - return 1; 319 - } 320 - 321 - if (tc_clsact_add(ys, ifi)) { 322 - ret = 2; 323 - goto err_destroy; 324 - } 325 - 326 - if (tc_filter_config(ys, ifi)) 327 - ret = 3; 328 - 329 - if (tc_clsact_del(ys, ifi)) 330 - ret = 4; 331 - 332 - err_destroy: 333 - ynl_sock_destroy(ys); 334 - return ret; 335 - }
-80
tools/net/ynl/samples/tc.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <stdio.h> 3 - #include <string.h> 4 - 5 - #include <ynl.h> 6 - 7 - #include <net/if.h> 8 - 9 - #include "tc-user.h" 10 - 11 - static void tc_qdisc_print(struct tc_getqdisc_rsp *q) 12 - { 13 - char ifname[IF_NAMESIZE]; 14 - const char *name; 15 - 16 - name = if_indextoname(q->_hdr.tcm_ifindex, ifname); 17 - if (name) 18 - printf("%16s: ", name); 19 - 20 - if (q->_len.kind) { 21 - printf("%s ", q->kind); 22 - 23 - if (q->options._present.fq_codel) { 24 - struct tc_fq_codel_attrs *fq_codel; 25 - struct tc_fq_codel_xstats *stats; 26 - 27 - fq_codel = &q->options.fq_codel; 28 - stats = q->stats2.app.fq_codel; 29 - 30 - if (fq_codel->_present.limit) 31 - printf("limit: %dp ", fq_codel->limit); 32 - if (fq_codel->_present.target) 33 - printf("target: %dms ", 34 - (fq_codel->target + 500) / 1000); 35 - if (q->stats2.app._len.fq_codel) 36 - printf("new_flow_cnt: %d ", 37 - stats->qdisc_stats.new_flow_count); 38 - } 39 - } 40 - 41 - printf("\n"); 42 - } 43 - 44 - int main(int argc, char **argv) 45 - { 46 - struct tc_getqdisc_req_dump *req; 47 - struct tc_getqdisc_list *rsp; 48 - struct ynl_error yerr; 49 - struct ynl_sock *ys; 50 - 51 - ys = ynl_sock_create(&ynl_tc_family, &yerr); 52 - if (!ys) { 53 - fprintf(stderr, "YNL: %s\n", yerr.msg); 54 - return 1; 55 - } 56 - 57 - req = tc_getqdisc_req_dump_alloc(); 58 - if (!req) 59 - goto err_destroy; 60 - 61 - rsp = tc_getqdisc_dump(ys, req); 62 - tc_getqdisc_req_dump_free(req); 63 - if (!rsp) 64 - goto err_close; 65 - 66 - if (ynl_dump_empty(rsp)) 67 - fprintf(stderr, "Error: no addresses reported\n"); 68 - ynl_dump_foreach(rsp, qdisc) 69 - tc_qdisc_print(qdisc); 70 - tc_getqdisc_list_free(rsp); 71 - 72 - ynl_sock_destroy(ys); 73 - return 0; 74 - 75 - err_close: 76 - fprintf(stderr, "YNL: %s\n", ys->err.msg); 77 - err_destroy: 78 - ynl_sock_destroy(ys); 79 - return 2; 80 - }
+64 -6
tools/net/ynl/tests/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 # Makefile for YNL tests 3 3 4 + include ../Makefile.deps 5 + 6 + CC=gcc 7 + CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ 8 + -I../lib/ -I../generated/ -I../../../testing/selftests/ \ 9 + -idirafter $(UAPI_PATH) 10 + ifneq ("$(NDEBUG)","1") 11 + CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan 12 + endif 13 + 14 + LDLIBS=../lib/ynl.a ../generated/protos.a 15 + 4 16 TEST_PROGS := \ 17 + devlink.sh \ 18 + ethtool.sh \ 19 + rt-addr.sh \ 20 + rt-route.sh \ 5 21 test_ynl_cli.sh \ 6 22 test_ynl_ethtool.sh \ 7 23 # end of TEST_PROGS 8 24 25 + TEST_GEN_PROGS := \ 26 + netdev \ 27 + ovs \ 28 + rt-link \ 29 + tc \ 30 + # end of TEST_GEN_PROGS 31 + 32 + TEST_GEN_FILES := \ 33 + devlink \ 34 + ethtool \ 35 + rt-addr \ 36 + rt-route \ 37 + # end of TEST_GEN_FILES 38 + 39 + TEST_FILES := ynl_nsim_lib.sh 40 + 41 + CFLAGS_netdev:=$(CFLAGS_netdev) $(CFLAGS_rt-link) 42 + CFLAGS_ovs:=$(CFLAGS_ovs_datapath) 43 + 44 + include $(wildcard *.d) 45 + 9 46 INSTALL_PATH ?= $(DESTDIR)/usr/share/kselftest 10 47 11 - all: $(TEST_PROGS) 48 + all: $(TEST_GEN_PROGS) $(TEST_GEN_FILES) 49 + 50 + ../lib/ynl.a: 51 + @$(MAKE) -C ../lib 52 + 53 + ../generated/protos.a: 54 + @$(MAKE) -C ../generated 55 + 56 + $(TEST_GEN_PROGS) $(TEST_GEN_FILES): %: %.c ../lib/ynl.a ../generated/protos.a 57 + @echo -e '\tCC test $@' 58 + @$(COMPILE.c) $(CFLAGS_$@) $@.c -o $@.o 59 + @$(LINK.c) $@.o -o $@ $(LDLIBS) 12 60 13 61 run_tests: 14 62 @for test in $(TEST_PROGS); do \ 15 63 ./$$test; \ 16 64 done 17 65 18 - install: $(TEST_PROGS) 66 + install: $(TEST_GEN_PROGS) $(TEST_GEN_FILES) 19 67 @mkdir -p $(INSTALL_PATH)/ynl 20 68 @cp ../../../testing/selftests/kselftest/ktap_helpers.sh $(INSTALL_PATH)/ 21 69 @for test in $(TEST_PROGS); do \ ··· 74 26 $$test > $(INSTALL_PATH)/ynl/$$name; \ 75 27 chmod +x $(INSTALL_PATH)/ynl/$$name; \ 76 28 done 77 - @for test in $(TEST_PROGS); do \ 29 + @for file in $(TEST_FILES); do \ 30 + cp $$file $(INSTALL_PATH)/ynl/$$file; \ 31 + done 32 + @for bin in $(TEST_GEN_PROGS) $(TEST_GEN_FILES); do \ 33 + cp $$bin $(INSTALL_PATH)/ynl/$$bin; \ 34 + done 35 + @for test in $(TEST_PROGS) $(TEST_GEN_PROGS); do \ 78 36 echo "ynl:$$test"; \ 79 37 done > $(INSTALL_PATH)/kselftest-list.txt 80 38 81 - clean distclean: 82 - @# Nothing to clean 39 + clean: 40 + rm -f *.o *.d *~ 83 41 84 - .PHONY: all install clean run_tests 42 + distclean: clean 43 + rm -f $(TEST_GEN_PROGS) $(TEST_GEN_FILES) 44 + 45 + .PHONY: all install clean distclean run_tests 46 + .DEFAULT_GOAL=all
+8
tools/net/ynl/tests/config
··· 1 1 CONFIG_DUMMY=m 2 2 CONFIG_INET_DIAG=y 3 3 CONFIG_IPV6=y 4 + CONFIG_NET_ACT_VLAN=m 5 + CONFIG_NET_CLS_ACT=y 6 + CONFIG_NET_CLS_FLOWER=m 7 + CONFIG_NET_SCH_FQ_CODEL=m 8 + CONFIG_NET_SCH_INGRESS=m 4 9 CONFIG_NET_NS=y 10 + CONFIG_NET_SCHED=y 5 11 CONFIG_NETDEVSIM=m 12 + CONFIG_NETKIT=y 13 + CONFIG_OPENVSWITCH=m 6 14 CONFIG_VETH=m
+101
tools/net/ynl/tests/devlink.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <kselftest_harness.h> 8 + 9 + #include "devlink-user.h" 10 + 11 + FIXTURE(devlink) 12 + { 13 + struct ynl_sock *ys; 14 + }; 15 + 16 + FIXTURE_SETUP(devlink) 17 + { 18 + self->ys = ynl_sock_create(&ynl_devlink_family, NULL); 19 + ASSERT_NE(NULL, self->ys) 20 + TH_LOG("failed to create devlink socket"); 21 + } 22 + 23 + FIXTURE_TEARDOWN(devlink) 24 + { 25 + ynl_sock_destroy(self->ys); 26 + } 27 + 28 + TEST_F(devlink, dump) 29 + { 30 + struct devlink_get_list *devs; 31 + 32 + devs = devlink_get_dump(self->ys); 33 + ASSERT_NE(NULL, devs) { 34 + TH_LOG("dump failed: %s", self->ys->err.msg); 35 + } 36 + 37 + if (ynl_dump_empty(devs)) { 38 + devlink_get_list_free(devs); 39 + SKIP(return, "no entries in dump"); 40 + } 41 + 42 + ynl_dump_foreach(devs, d) { 43 + EXPECT_TRUE((bool)d->_len.bus_name); 44 + EXPECT_TRUE((bool)d->_len.dev_name); 45 + ksft_print_msg("%s/%s\n", d->bus_name, d->dev_name); 46 + } 47 + 48 + devlink_get_list_free(devs); 49 + } 50 + 51 + TEST_F(devlink, info) 52 + { 53 + struct devlink_get_list *devs; 54 + 55 + devs = devlink_get_dump(self->ys); 56 + ASSERT_NE(NULL, devs) { 57 + TH_LOG("dump failed: %s", self->ys->err.msg); 58 + } 59 + 60 + if (ynl_dump_empty(devs)) { 61 + devlink_get_list_free(devs); 62 + SKIP(return, "no devices to query"); 63 + } 64 + 65 + ynl_dump_foreach(devs, d) { 66 + struct devlink_info_get_req *info_req; 67 + struct devlink_info_get_rsp *info_rsp; 68 + unsigned int i; 69 + 70 + EXPECT_TRUE((bool)d->_len.bus_name); 71 + EXPECT_TRUE((bool)d->_len.dev_name); 72 + ksft_print_msg("%s/%s:\n", d->bus_name, d->dev_name); 73 + 74 + info_req = devlink_info_get_req_alloc(); 75 + ASSERT_NE(NULL, info_req); 76 + devlink_info_get_req_set_bus_name(info_req, d->bus_name); 77 + devlink_info_get_req_set_dev_name(info_req, d->dev_name); 78 + 79 + info_rsp = devlink_info_get(self->ys, info_req); 80 + devlink_info_get_req_free(info_req); 81 + ASSERT_NE(NULL, info_rsp) { 82 + devlink_get_list_free(devs); 83 + TH_LOG("info_get failed: %s", self->ys->err.msg); 84 + } 85 + 86 + EXPECT_TRUE((bool)info_rsp->_len.info_driver_name); 87 + if (info_rsp->_len.info_driver_name) 88 + ksft_print_msg(" driver: %s\n", 89 + info_rsp->info_driver_name); 90 + if (info_rsp->_count.info_version_running) 91 + ksft_print_msg(" running fw:\n"); 92 + for (i = 0; i < info_rsp->_count.info_version_running; i++) 93 + ksft_print_msg(" %s: %s\n", 94 + info_rsp->info_version_running[i].info_version_name, 95 + info_rsp->info_version_running[i].info_version_value); 96 + devlink_info_get_rsp_free(info_rsp); 97 + } 98 + devlink_get_list_free(devs); 99 + } 100 + 101 + TEST_HARNESS_MAIN
+5
tools/net/ynl/tests/devlink.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + source "$(dirname "$(realpath "$0")")/ynl_nsim_lib.sh" 4 + nsim_setup 5 + "$(dirname "$(realpath "$0")")/devlink"
+92
tools/net/ynl/tests/ethtool.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <net/if.h> 8 + 9 + #include <kselftest_harness.h> 10 + 11 + #include "ethtool-user.h" 12 + 13 + FIXTURE(ethtool) 14 + { 15 + struct ynl_sock *ys; 16 + }; 17 + 18 + FIXTURE_SETUP(ethtool) 19 + { 20 + self->ys = ynl_sock_create(&ynl_ethtool_family, NULL); 21 + ASSERT_NE(NULL, self->ys) 22 + TH_LOG("failed to create ethtool socket"); 23 + } 24 + 25 + FIXTURE_TEARDOWN(ethtool) 26 + { 27 + ynl_sock_destroy(self->ys); 28 + } 29 + 30 + TEST_F(ethtool, channels) 31 + { 32 + struct ethtool_channels_get_req_dump creq = {}; 33 + struct ethtool_channels_get_list *channels; 34 + 35 + creq._present.header = 1; /* ethtool needs an empty nest */ 36 + channels = ethtool_channels_get_dump(self->ys, &creq); 37 + ASSERT_NE(NULL, channels) { 38 + TH_LOG("channels dump failed: %s", self->ys->err.msg); 39 + } 40 + 41 + if (ynl_dump_empty(channels)) { 42 + ethtool_channels_get_list_free(channels); 43 + SKIP(return, "no entries in channels dump"); 44 + } 45 + 46 + ynl_dump_foreach(channels, dev) { 47 + EXPECT_TRUE((bool)dev->header._len.dev_name); 48 + ksft_print_msg("%8s: ", dev->header.dev_name); 49 + EXPECT_TRUE(dev->_present.rx_count || 50 + dev->_present.tx_count || 51 + dev->_present.combined_count); 52 + if (dev->_present.rx_count) 53 + printf("rx %d ", dev->rx_count); 54 + if (dev->_present.tx_count) 55 + printf("tx %d ", dev->tx_count); 56 + if (dev->_present.combined_count) 57 + printf("combined %d ", dev->combined_count); 58 + printf("\n"); 59 + } 60 + ethtool_channels_get_list_free(channels); 61 + } 62 + 63 + TEST_F(ethtool, rings) 64 + { 65 + struct ethtool_rings_get_req_dump rreq = {}; 66 + struct ethtool_rings_get_list *rings; 67 + 68 + rreq._present.header = 1; /* ethtool needs an empty nest */ 69 + rings = ethtool_rings_get_dump(self->ys, &rreq); 70 + ASSERT_NE(NULL, rings) { 71 + TH_LOG("rings dump failed: %s", self->ys->err.msg); 72 + } 73 + 74 + if (ynl_dump_empty(rings)) { 75 + ethtool_rings_get_list_free(rings); 76 + SKIP(return, "no entries in rings dump"); 77 + } 78 + 79 + ynl_dump_foreach(rings, dev) { 80 + EXPECT_TRUE((bool)dev->header._len.dev_name); 81 + ksft_print_msg("%8s: ", dev->header.dev_name); 82 + EXPECT_TRUE(dev->_present.rx || dev->_present.tx); 83 + if (dev->_present.rx) 84 + printf("rx %d ", dev->rx); 85 + if (dev->_present.tx) 86 + printf("tx %d ", dev->tx); 87 + printf("\n"); 88 + } 89 + ethtool_rings_get_list_free(rings); 90 + } 91 + 92 + TEST_HARNESS_MAIN
+5
tools/net/ynl/tests/ethtool.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + source "$(dirname "$(realpath "$0")")/ynl_nsim_lib.sh" 4 + nsim_setup 5 + "$(dirname "$(realpath "$0")")/ethtool"
+231
tools/net/ynl/tests/netdev.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <net/if.h> 8 + 9 + #include <kselftest_harness.h> 10 + 11 + #include "netdev-user.h" 12 + #include "rt-link-user.h" 13 + 14 + static void netdev_print_device(struct __test_metadata *_metadata, 15 + struct netdev_dev_get_rsp *d, unsigned int op) 16 + { 17 + char ifname[IF_NAMESIZE]; 18 + const char *name; 19 + 20 + EXPECT_TRUE((bool)d->_present.ifindex); 21 + if (!d->_present.ifindex) 22 + return; 23 + 24 + name = if_indextoname(d->ifindex, ifname); 25 + EXPECT_TRUE((bool)name); 26 + if (name) 27 + ksft_print_msg("%8s[%d]\t", name, d->ifindex); 28 + else 29 + ksft_print_msg("[%d]\t", d->ifindex); 30 + 31 + EXPECT_TRUE((bool)d->_present.xdp_features); 32 + if (!d->_present.xdp_features) 33 + return; 34 + 35 + printf("xdp-features (%llx):", d->xdp_features); 36 + for (int i = 0; d->xdp_features >= 1U << i; i++) { 37 + if (d->xdp_features & (1U << i)) 38 + printf(" %s", netdev_xdp_act_str(1 << i)); 39 + } 40 + 41 + printf(" xdp-rx-metadata-features (%llx):", 42 + d->xdp_rx_metadata_features); 43 + for (int i = 0; d->xdp_rx_metadata_features >= 1U << i; i++) { 44 + if (d->xdp_rx_metadata_features & (1U << i)) 45 + printf(" %s", 46 + netdev_xdp_rx_metadata_str(1 << i)); 47 + } 48 + 49 + printf(" xsk-features (%llx):", d->xsk_features); 50 + for (int i = 0; d->xsk_features >= 1U << i; i++) { 51 + if (d->xsk_features & (1U << i)) 52 + printf(" %s", netdev_xsk_flags_str(1 << i)); 53 + } 54 + 55 + printf(" xdp-zc-max-segs=%u", d->xdp_zc_max_segs); 56 + 57 + name = netdev_op_str(op); 58 + if (name) 59 + printf(" (ntf: %s)", name); 60 + printf("\n"); 61 + } 62 + 63 + static int veth_create(struct ynl_sock *ys_link) 64 + { 65 + struct rt_link_getlink_ntf *ntf_gl; 66 + struct rt_link_newlink_req *req; 67 + struct ynl_ntf_base_type *ntf; 68 + int ret; 69 + 70 + req = rt_link_newlink_req_alloc(); 71 + if (!req) 72 + return -1; 73 + 74 + rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); 75 + rt_link_newlink_req_set_linkinfo_kind(req, "veth"); 76 + 77 + ret = rt_link_newlink(ys_link, req); 78 + rt_link_newlink_req_free(req); 79 + if (ret) 80 + return -1; 81 + 82 + if (!ynl_has_ntf(ys_link)) 83 + return 0; 84 + 85 + ntf = ynl_ntf_dequeue(ys_link); 86 + if (!ntf || ntf->cmd != RTM_NEWLINK) { 87 + ynl_ntf_free(ntf); 88 + return 0; 89 + } 90 + ntf_gl = (void *)ntf; 91 + ret = ntf_gl->obj._hdr.ifi_index; 92 + ynl_ntf_free(ntf); 93 + 94 + return ret; 95 + } 96 + 97 + static void veth_delete(struct __test_metadata *_metadata, 98 + struct ynl_sock *ys_link, int ifindex) 99 + { 100 + struct rt_link_dellink_req *req; 101 + 102 + req = rt_link_dellink_req_alloc(); 103 + ASSERT_NE(NULL, req); 104 + 105 + req->_hdr.ifi_index = ifindex; 106 + EXPECT_EQ(0, rt_link_dellink(ys_link, req)); 107 + rt_link_dellink_req_free(req); 108 + } 109 + 110 + FIXTURE(netdev) 111 + { 112 + struct ynl_sock *ys; 113 + struct ynl_sock *ys_link; 114 + }; 115 + 116 + FIXTURE_SETUP(netdev) 117 + { 118 + struct ynl_error yerr; 119 + 120 + self->ys = ynl_sock_create(&ynl_netdev_family, &yerr); 121 + ASSERT_NE(NULL, self->ys) { 122 + TH_LOG("Failed to create YNL netdev socket: %s", yerr.msg); 123 + } 124 + } 125 + 126 + FIXTURE_TEARDOWN(netdev) 127 + { 128 + if (self->ys_link) 129 + ynl_sock_destroy(self->ys_link); 130 + ynl_sock_destroy(self->ys); 131 + } 132 + 133 + TEST_F(netdev, dump) 134 + { 135 + struct netdev_dev_get_list *devs; 136 + 137 + devs = netdev_dev_get_dump(self->ys); 138 + ASSERT_NE(NULL, devs) { 139 + TH_LOG("dump failed: %s", self->ys->err.msg); 140 + } 141 + 142 + if (ynl_dump_empty(devs)) { 143 + netdev_dev_get_list_free(devs); 144 + SKIP(return, "no entries in dump"); 145 + } 146 + 147 + ynl_dump_foreach(devs, d) 148 + netdev_print_device(_metadata, d, 0); 149 + 150 + netdev_dev_get_list_free(devs); 151 + } 152 + 153 + TEST_F(netdev, get) 154 + { 155 + struct netdev_dev_get_list *devs; 156 + struct netdev_dev_get_req *req; 157 + struct netdev_dev_get_rsp *dev; 158 + int ifindex = 0; 159 + 160 + devs = netdev_dev_get_dump(self->ys); 161 + ASSERT_NE(NULL, devs) { 162 + TH_LOG("dump failed: %s", self->ys->err.msg); 163 + } 164 + 165 + ynl_dump_foreach(devs, d) { 166 + if (d->_present.ifindex) { 167 + ifindex = d->ifindex; 168 + break; 169 + } 170 + } 171 + netdev_dev_get_list_free(devs); 172 + 173 + if (!ifindex) 174 + SKIP(return, "no device to query"); 175 + 176 + req = netdev_dev_get_req_alloc(); 177 + ASSERT_NE(NULL, req); 178 + netdev_dev_get_req_set_ifindex(req, ifindex); 179 + 180 + dev = netdev_dev_get(self->ys, req); 181 + netdev_dev_get_req_free(req); 182 + ASSERT_NE(NULL, dev) { 183 + TH_LOG("dev_get failed: %s", self->ys->err.msg); 184 + } 185 + 186 + netdev_print_device(_metadata, dev, 0); 187 + netdev_dev_get_rsp_free(dev); 188 + } 189 + 190 + TEST_F(netdev, ntf_check) 191 + { 192 + struct ynl_ntf_base_type *ntf; 193 + int veth_ifindex; 194 + bool received; 195 + int ret; 196 + 197 + ret = ynl_subscribe(self->ys, "mgmt"); 198 + ASSERT_EQ(0, ret) { 199 + TH_LOG("subscribe failed: %s", self->ys->err.msg); 200 + } 201 + 202 + self->ys_link = ynl_sock_create(&ynl_rt_link_family, NULL); 203 + ASSERT_NE(NULL, self->ys_link) 204 + TH_LOG("failed to create rt-link socket"); 205 + 206 + veth_ifindex = veth_create(self->ys_link); 207 + ASSERT_GT(veth_ifindex, 0) 208 + TH_LOG("failed to create veth"); 209 + 210 + ynl_ntf_check(self->ys); 211 + 212 + ntf = ynl_ntf_dequeue(self->ys); 213 + received = ntf; 214 + if (ntf) { 215 + netdev_print_device(_metadata, 216 + (struct netdev_dev_get_rsp *)&ntf->data, 217 + ntf->cmd); 218 + ynl_ntf_free(ntf); 219 + } 220 + 221 + /* Drain any remaining notifications */ 222 + while ((ntf = ynl_ntf_dequeue(self->ys))) 223 + ynl_ntf_free(ntf); 224 + 225 + veth_delete(_metadata, self->ys_link, veth_ifindex); 226 + 227 + ASSERT_TRUE(received) 228 + TH_LOG("no notification received"); 229 + } 230 + 231 + TEST_HARNESS_MAIN
+108
tools/net/ynl/tests/ovs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <kselftest_harness.h> 8 + 9 + #include "ovs_datapath-user.h" 10 + 11 + static void ovs_print_datapath(struct __test_metadata *_metadata, 12 + struct ovs_datapath_get_rsp *dp) 13 + { 14 + EXPECT_TRUE((bool)dp->_len.name); 15 + if (!dp->_len.name) 16 + return; 17 + 18 + EXPECT_TRUE((bool)dp->_hdr.dp_ifindex); 19 + ksft_print_msg("%s(%d): pid:%u cache:%u\n", 20 + dp->name, dp->_hdr.dp_ifindex, 21 + dp->upcall_pid, dp->masks_cache_size); 22 + } 23 + 24 + FIXTURE(ovs) 25 + { 26 + struct ynl_sock *ys; 27 + char *dp_name; 28 + }; 29 + 30 + FIXTURE_SETUP(ovs) 31 + { 32 + self->ys = ynl_sock_create(&ynl_ovs_datapath_family, NULL); 33 + ASSERT_NE(NULL, self->ys) 34 + TH_LOG("failed to create OVS datapath socket"); 35 + } 36 + 37 + FIXTURE_TEARDOWN(ovs) 38 + { 39 + if (self->dp_name) { 40 + struct ovs_datapath_del_req *req; 41 + 42 + req = ovs_datapath_del_req_alloc(); 43 + if (req) { 44 + ovs_datapath_del_req_set_name(req, self->dp_name); 45 + ovs_datapath_del(self->ys, req); 46 + ovs_datapath_del_req_free(req); 47 + } 48 + } 49 + ynl_sock_destroy(self->ys); 50 + } 51 + 52 + TEST_F(ovs, crud) 53 + { 54 + struct ovs_datapath_get_req_dump *dreq; 55 + struct ovs_datapath_new_req *new_req; 56 + struct ovs_datapath_get_list *dps; 57 + struct ovs_datapath_get_rsp *dp; 58 + struct ovs_datapath_get_req *req; 59 + bool found = false; 60 + int err; 61 + 62 + new_req = ovs_datapath_new_req_alloc(); 63 + ASSERT_NE(NULL, new_req); 64 + ovs_datapath_new_req_set_upcall_pid(new_req, 1); 65 + ovs_datapath_new_req_set_name(new_req, "ynl-test"); 66 + 67 + err = ovs_datapath_new(self->ys, new_req); 68 + ovs_datapath_new_req_free(new_req); 69 + ASSERT_EQ(0, err) { 70 + TH_LOG("new failed: %s", self->ys->err.msg); 71 + } 72 + self->dp_name = "ynl-test"; 73 + 74 + ksft_print_msg("get:\n"); 75 + req = ovs_datapath_get_req_alloc(); 76 + ASSERT_NE(NULL, req); 77 + ovs_datapath_get_req_set_name(req, "ynl-test"); 78 + 79 + dp = ovs_datapath_get(self->ys, req); 80 + ovs_datapath_get_req_free(req); 81 + ASSERT_NE(NULL, dp) { 82 + TH_LOG("get failed: %s", self->ys->err.msg); 83 + } 84 + 85 + ovs_print_datapath(_metadata, dp); 86 + EXPECT_STREQ("ynl-test", dp->name); 87 + ovs_datapath_get_rsp_free(dp); 88 + 89 + ksft_print_msg("dump:\n"); 90 + dreq = ovs_datapath_get_req_dump_alloc(); 91 + ASSERT_NE(NULL, dreq); 92 + 93 + dps = ovs_datapath_get_dump(self->ys, dreq); 94 + ovs_datapath_get_req_dump_free(dreq); 95 + ASSERT_NE(NULL, dps) { 96 + TH_LOG("dump failed: %s", self->ys->err.msg); 97 + } 98 + 99 + ynl_dump_foreach(dps, d) { 100 + ovs_print_datapath(_metadata, d); 101 + if (d->name && !strcmp(d->name, "ynl-test")) 102 + found = true; 103 + } 104 + ovs_datapath_get_list_free(dps); 105 + EXPECT_TRUE(found); 106 + } 107 + 108 + TEST_HARNESS_MAIN
+111
tools/net/ynl/tests/rt-addr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <arpa/inet.h> 8 + #include <net/if.h> 9 + 10 + #include <kselftest_harness.h> 11 + 12 + #include "rt-addr-user.h" 13 + 14 + static void rt_addr_print(struct __test_metadata *_metadata, 15 + struct rt_addr_getaddr_rsp *a) 16 + { 17 + char ifname[IF_NAMESIZE]; 18 + char addr_str[64]; 19 + const char *addr; 20 + const char *name; 21 + 22 + name = if_indextoname(a->_hdr.ifa_index, ifname); 23 + EXPECT_NE(NULL, name); 24 + if (name) 25 + ksft_print_msg("%16s: ", name); 26 + 27 + EXPECT_TRUE(a->_len.address == 4 || a->_len.address == 16); 28 + switch (a->_len.address) { 29 + case 4: 30 + addr = inet_ntop(AF_INET, a->address, 31 + addr_str, sizeof(addr_str)); 32 + break; 33 + case 16: 34 + addr = inet_ntop(AF_INET6, a->address, 35 + addr_str, sizeof(addr_str)); 36 + break; 37 + default: 38 + addr = NULL; 39 + break; 40 + } 41 + if (addr) 42 + printf("%s", addr); 43 + else 44 + printf("[%d]", a->_len.address); 45 + 46 + printf("\n"); 47 + } 48 + 49 + FIXTURE(rt_addr) 50 + { 51 + struct ynl_sock *ys; 52 + }; 53 + 54 + FIXTURE_SETUP(rt_addr) 55 + { 56 + struct ynl_error yerr; 57 + 58 + self->ys = ynl_sock_create(&ynl_rt_addr_family, &yerr); 59 + ASSERT_NE(NULL, self->ys) 60 + TH_LOG("failed to create rt-addr socket: %s", yerr.msg); 61 + } 62 + 63 + FIXTURE_TEARDOWN(rt_addr) 64 + { 65 + ynl_sock_destroy(self->ys); 66 + } 67 + 68 + TEST_F(rt_addr, dump) 69 + { 70 + struct rt_addr_getaddr_list *rsp; 71 + struct rt_addr_getaddr_req *req; 72 + struct in6_addr v6_expected; 73 + struct in_addr v4_expected; 74 + bool found_v4 = false; 75 + bool found_v6 = false; 76 + 77 + /* The bash wrapper for this test adds these addresses on nsim0, 78 + * make sure we can find them in the dump. 79 + */ 80 + inet_pton(AF_INET, "192.168.1.1", &v4_expected); 81 + inet_pton(AF_INET6, "2001:db8::1", &v6_expected); 82 + 83 + req = rt_addr_getaddr_req_alloc(); 84 + ASSERT_NE(NULL, req); 85 + 86 + rsp = rt_addr_getaddr_dump(self->ys, req); 87 + rt_addr_getaddr_req_free(req); 88 + ASSERT_NE(NULL, rsp) { 89 + TH_LOG("dump failed: %s", self->ys->err.msg); 90 + } 91 + 92 + ASSERT_FALSE(ynl_dump_empty(rsp)) { 93 + rt_addr_getaddr_list_free(rsp); 94 + TH_LOG("no addresses reported"); 95 + } 96 + 97 + ynl_dump_foreach(rsp, addr) { 98 + rt_addr_print(_metadata, addr); 99 + 100 + found_v4 |= addr->_len.address == 4 && 101 + !memcmp(addr->address, &v4_expected, 4); 102 + found_v6 |= addr->_len.address == 16 && 103 + !memcmp(addr->address, &v6_expected, 16); 104 + } 105 + rt_addr_getaddr_list_free(rsp); 106 + 107 + EXPECT_TRUE(found_v4); 108 + EXPECT_TRUE(found_v6); 109 + } 110 + 111 + TEST_HARNESS_MAIN
+5
tools/net/ynl/tests/rt-addr.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + source "$(dirname "$(realpath "$0")")/ynl_nsim_lib.sh" 4 + nsim_setup 5 + "$(dirname "$(realpath "$0")")/rt-addr"
+206
tools/net/ynl/tests/rt-link.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <arpa/inet.h> 8 + #include <net/if.h> 9 + 10 + #include <kselftest_harness.h> 11 + 12 + #include "rt-link-user.h" 13 + 14 + static void rt_link_print(struct __test_metadata *_metadata, 15 + struct rt_link_getlink_rsp *r) 16 + { 17 + unsigned int i; 18 + 19 + EXPECT_TRUE((bool)r->_hdr.ifi_index); 20 + ksft_print_msg("%3d: ", r->_hdr.ifi_index); 21 + 22 + EXPECT_TRUE((bool)r->_len.ifname); 23 + if (r->_len.ifname) 24 + printf("%6s: ", r->ifname); 25 + 26 + if (r->_present.mtu) 27 + printf("mtu %5d ", r->mtu); 28 + 29 + if (r->linkinfo._len.kind) 30 + printf("kind %-8s ", r->linkinfo.kind); 31 + else 32 + printf(" %8s ", ""); 33 + 34 + if (r->prop_list._count.alt_ifname) { 35 + printf("altname "); 36 + for (i = 0; i < r->prop_list._count.alt_ifname; i++) 37 + printf("%s ", r->prop_list.alt_ifname[i]->str); 38 + printf(" "); 39 + } 40 + 41 + if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) { 42 + struct rt_link_linkinfo_netkit_attrs *netkit; 43 + const char *name; 44 + 45 + netkit = &r->linkinfo.data.netkit; 46 + printf("primary %d ", netkit->primary); 47 + 48 + name = NULL; 49 + if (netkit->_present.policy) 50 + name = rt_link_netkit_policy_str(netkit->policy); 51 + if (name) 52 + printf("policy %s ", name); 53 + } 54 + 55 + printf("\n"); 56 + } 57 + 58 + static int netkit_create(struct ynl_sock *ys) 59 + { 60 + struct rt_link_getlink_ntf *ntf_gl; 61 + struct rt_link_newlink_req *req; 62 + struct ynl_ntf_base_type *ntf; 63 + int ret; 64 + 65 + req = rt_link_newlink_req_alloc(); 66 + if (!req) 67 + return -1; 68 + 69 + rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); 70 + rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); 71 + rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP); 72 + 73 + ret = rt_link_newlink(ys, req); 74 + rt_link_newlink_req_free(req); 75 + if (ret) 76 + return -1; 77 + 78 + if (!ynl_has_ntf(ys)) 79 + return 0; 80 + 81 + ntf = ynl_ntf_dequeue(ys); 82 + if (!ntf || ntf->cmd != RTM_NEWLINK) { 83 + ynl_ntf_free(ntf); 84 + return 0; 85 + } 86 + ntf_gl = (void *)ntf; 87 + ret = ntf_gl->obj._hdr.ifi_index; 88 + ynl_ntf_free(ntf); 89 + 90 + return ret; 91 + } 92 + 93 + static void netkit_delete(struct __test_metadata *_metadata, 94 + struct ynl_sock *ys, int ifindex) 95 + { 96 + struct rt_link_dellink_req *req; 97 + 98 + req = rt_link_dellink_req_alloc(); 99 + ASSERT_NE(NULL, req); 100 + 101 + req->_hdr.ifi_index = ifindex; 102 + EXPECT_EQ(0, rt_link_dellink(ys, req)); 103 + rt_link_dellink_req_free(req); 104 + } 105 + 106 + FIXTURE(rt_link) 107 + { 108 + struct ynl_sock *ys; 109 + }; 110 + 111 + FIXTURE_SETUP(rt_link) 112 + { 113 + struct ynl_error yerr; 114 + 115 + self->ys = ynl_sock_create(&ynl_rt_link_family, &yerr); 116 + ASSERT_NE(NULL, self->ys) { 117 + TH_LOG("failed to create rt-link socket: %s", yerr.msg); 118 + } 119 + } 120 + 121 + FIXTURE_TEARDOWN(rt_link) 122 + { 123 + ynl_sock_destroy(self->ys); 124 + } 125 + 126 + TEST_F(rt_link, dump) 127 + { 128 + struct rt_link_getlink_req_dump *req; 129 + struct rt_link_getlink_list *rsp; 130 + 131 + req = rt_link_getlink_req_dump_alloc(); 132 + ASSERT_NE(NULL, req); 133 + rsp = rt_link_getlink_dump(self->ys, req); 134 + rt_link_getlink_req_dump_free(req); 135 + ASSERT_NE(NULL, rsp) { 136 + TH_LOG("dump failed: %s", self->ys->err.msg); 137 + } 138 + ASSERT_FALSE(ynl_dump_empty(rsp)); 139 + 140 + ynl_dump_foreach(rsp, link) 141 + rt_link_print(_metadata, link); 142 + 143 + rt_link_getlink_list_free(rsp); 144 + } 145 + 146 + TEST_F(rt_link, netkit) 147 + { 148 + struct rt_link_getlink_req_dump *dreq; 149 + struct rt_link_getlink_list *rsp; 150 + bool found = false; 151 + int netkit_ifindex; 152 + 153 + /* Create netkit with valid policy */ 154 + netkit_ifindex = netkit_create(self->ys); 155 + ASSERT_GT(netkit_ifindex, 0) 156 + TH_LOG("failed to create netkit: %s", self->ys->err.msg); 157 + 158 + /* Verify it appears in a dump */ 159 + dreq = rt_link_getlink_req_dump_alloc(); 160 + ASSERT_NE(NULL, dreq); 161 + rsp = rt_link_getlink_dump(self->ys, dreq); 162 + rt_link_getlink_req_dump_free(dreq); 163 + ASSERT_NE(NULL, rsp) { 164 + TH_LOG("dump failed: %s", self->ys->err.msg); 165 + } 166 + 167 + ynl_dump_foreach(rsp, link) { 168 + if (link->_hdr.ifi_index == netkit_ifindex) { 169 + rt_link_print(_metadata, link); 170 + found = true; 171 + } 172 + } 173 + rt_link_getlink_list_free(rsp); 174 + EXPECT_TRUE(found); 175 + 176 + netkit_delete(_metadata, self->ys, netkit_ifindex); 177 + } 178 + 179 + TEST_F(rt_link, netkit_err_msg) 180 + { 181 + struct rt_link_newlink_req *req; 182 + int ret; 183 + 184 + /* Test creating netkit with bad policy - should fail */ 185 + req = rt_link_newlink_req_alloc(); 186 + ASSERT_NE(NULL, req); 187 + rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE); 188 + rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); 189 + rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10); 190 + 191 + ret = rt_link_newlink(self->ys, req); 192 + rt_link_newlink_req_free(req); 193 + EXPECT_NE(0, ret) { 194 + TH_LOG("creating netkit with bad policy should fail"); 195 + } 196 + 197 + /* Expect: 198 + * Kernel error: 'Provided default xmit policy not supported' (bad attribute: .linkinfo.data(netkit).policy) 199 + */ 200 + EXPECT_NE(NULL, strstr(self->ys->err.msg, "bad attribute: .linkinfo.data(netkit).policy")) { 201 + TH_LOG("expected extack msg not found: %s", 202 + self->ys->err.msg); 203 + } 204 + } 205 + 206 + TEST_HARNESS_MAIN
+113
tools/net/ynl/tests/rt-route.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <arpa/inet.h> 8 + #include <net/if.h> 9 + 10 + #include <kselftest_harness.h> 11 + 12 + #include "rt-route-user.h" 13 + 14 + static void rt_route_print(struct __test_metadata *_metadata, 15 + struct rt_route_getroute_rsp *r) 16 + { 17 + char ifname[IF_NAMESIZE]; 18 + char route_str[64]; 19 + const char *route; 20 + const char *name; 21 + 22 + /* Ignore local */ 23 + if (r->_hdr.rtm_table == RT_TABLE_LOCAL) 24 + return; 25 + 26 + if (r->_present.oif) { 27 + name = if_indextoname(r->oif, ifname); 28 + EXPECT_NE(NULL, name); 29 + if (name) 30 + ksft_print_msg("oif: %-16s ", name); 31 + } 32 + 33 + if (r->_len.dst) { 34 + route = inet_ntop(r->_hdr.rtm_family, r->dst, 35 + route_str, sizeof(route_str)); 36 + printf("dst: %s/%d", route, r->_hdr.rtm_dst_len); 37 + } 38 + 39 + if (r->_len.gateway) { 40 + route = inet_ntop(r->_hdr.rtm_family, r->gateway, 41 + route_str, sizeof(route_str)); 42 + printf("gateway: %s ", route); 43 + } 44 + 45 + printf("\n"); 46 + } 47 + 48 + FIXTURE(rt_route) 49 + { 50 + struct ynl_sock *ys; 51 + }; 52 + 53 + FIXTURE_SETUP(rt_route) 54 + { 55 + struct ynl_error yerr; 56 + 57 + self->ys = ynl_sock_create(&ynl_rt_route_family, &yerr); 58 + ASSERT_NE(NULL, self->ys) 59 + TH_LOG("failed to create rt-route socket: %s", yerr.msg); 60 + } 61 + 62 + FIXTURE_TEARDOWN(rt_route) 63 + { 64 + ynl_sock_destroy(self->ys); 65 + } 66 + 67 + TEST_F(rt_route, dump) 68 + { 69 + struct rt_route_getroute_req_dump *req; 70 + struct rt_route_getroute_list *rsp; 71 + struct in6_addr v6_expected; 72 + struct in_addr v4_expected; 73 + bool found_v4 = false; 74 + bool found_v6 = false; 75 + 76 + /* The bash wrapper configures 192.168.1.1/24 and 2001:db8::1/64, 77 + * make sure we can find the connected routes in the dump. 78 + */ 79 + inet_pton(AF_INET, "192.168.1.0", &v4_expected); 80 + inet_pton(AF_INET6, "2001:db8::", &v6_expected); 81 + 82 + req = rt_route_getroute_req_dump_alloc(); 83 + ASSERT_NE(NULL, req); 84 + 85 + rsp = rt_route_getroute_dump(self->ys, req); 86 + rt_route_getroute_req_dump_free(req); 87 + ASSERT_NE(NULL, rsp) { 88 + TH_LOG("dump failed: %s", self->ys->err.msg); 89 + } 90 + 91 + ASSERT_FALSE(ynl_dump_empty(rsp)) { 92 + rt_route_getroute_list_free(rsp); 93 + TH_LOG("no routes reported"); 94 + } 95 + 96 + ynl_dump_foreach(rsp, route) { 97 + rt_route_print(_metadata, route); 98 + 99 + if (route->_hdr.rtm_table == RT_TABLE_LOCAL) 100 + continue; 101 + 102 + if (route->_len.dst == 4 && route->_hdr.rtm_dst_len == 24) 103 + found_v4 |= !memcmp(route->dst, &v4_expected, 4); 104 + if (route->_len.dst == 16 && route->_hdr.rtm_dst_len == 64) 105 + found_v6 |= !memcmp(route->dst, &v6_expected, 16); 106 + } 107 + rt_route_getroute_list_free(rsp); 108 + 109 + EXPECT_TRUE(found_v4); 110 + EXPECT_TRUE(found_v6); 111 + } 112 + 113 + TEST_HARNESS_MAIN
+5
tools/net/ynl/tests/rt-route.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + source "$(dirname "$(realpath "$0")")/ynl_nsim_lib.sh" 4 + nsim_setup 5 + "$(dirname "$(realpath "$0")")/rt-route"
+409
tools/net/ynl/tests/tc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #define _GNU_SOURCE 3 + #include <sched.h> 4 + #include <stdio.h> 5 + #include <string.h> 6 + #include <stdlib.h> 7 + #include <arpa/inet.h> 8 + #include <linux/pkt_sched.h> 9 + #include <linux/tc_act/tc_vlan.h> 10 + #include <linux/tc_act/tc_gact.h> 11 + #include <linux/if_ether.h> 12 + #include <net/if.h> 13 + 14 + #include <ynl.h> 15 + 16 + #include <kselftest_harness.h> 17 + 18 + #include "tc-user.h" 19 + 20 + #define TC_HANDLE (0xFFFF << 16) 21 + 22 + static bool tc_qdisc_print(struct __test_metadata *_metadata, 23 + struct tc_getqdisc_rsp *q) 24 + { 25 + bool was_fq_codel = false; 26 + char ifname[IF_NAMESIZE]; 27 + const char *name; 28 + 29 + name = if_indextoname(q->_hdr.tcm_ifindex, ifname); 30 + EXPECT_TRUE((bool)name); 31 + ksft_print_msg("%16s: ", name ?: "no-name"); 32 + 33 + if (q->_len.kind) { 34 + printf("%s ", q->kind); 35 + 36 + if (q->options._present.fq_codel) { 37 + struct tc_fq_codel_attrs *fq_codel; 38 + struct tc_fq_codel_xstats *stats; 39 + 40 + fq_codel = &q->options.fq_codel; 41 + stats = q->stats2.app.fq_codel; 42 + 43 + EXPECT_EQ(true, 44 + fq_codel->_present.limit && 45 + fq_codel->_present.target && 46 + q->stats2.app._len.fq_codel); 47 + 48 + if (fq_codel->_present.limit) 49 + printf("limit: %dp ", fq_codel->limit); 50 + if (fq_codel->_present.target) 51 + printf("target: %dms ", 52 + (fq_codel->target + 500) / 1000); 53 + if (q->stats2.app._len.fq_codel) 54 + printf("new_flow_cnt: %d ", 55 + stats->qdisc_stats.new_flow_count); 56 + was_fq_codel = true; 57 + } 58 + } 59 + printf("\n"); 60 + 61 + return was_fq_codel; 62 + } 63 + 64 + static const char *vlan_act_name(struct tc_vlan *p) 65 + { 66 + switch (p->v_action) { 67 + case TCA_VLAN_ACT_POP: 68 + return "pop"; 69 + case TCA_VLAN_ACT_PUSH: 70 + return "push"; 71 + case TCA_VLAN_ACT_MODIFY: 72 + return "modify"; 73 + default: 74 + break; 75 + } 76 + 77 + return "not supported"; 78 + } 79 + 80 + static const char *gact_act_name(struct tc_gact *p) 81 + { 82 + switch (p->action) { 83 + case TC_ACT_SHOT: 84 + return "drop"; 85 + case TC_ACT_OK: 86 + return "ok"; 87 + case TC_ACT_PIPE: 88 + return "pipe"; 89 + default: 90 + break; 91 + } 92 + 93 + return "not supported"; 94 + } 95 + 96 + static void print_vlan(struct tc_act_vlan_attrs *vlan) 97 + { 98 + printf("%s ", vlan_act_name(vlan->parms)); 99 + if (vlan->_present.push_vlan_id) 100 + printf("id %u ", vlan->push_vlan_id); 101 + if (vlan->_present.push_vlan_protocol) 102 + printf("protocol %#x ", ntohs(vlan->push_vlan_protocol)); 103 + if (vlan->_present.push_vlan_priority) 104 + printf("priority %u ", vlan->push_vlan_priority); 105 + } 106 + 107 + static void print_gact(struct tc_act_gact_attrs *gact) 108 + { 109 + struct tc_gact *p = gact->parms; 110 + 111 + printf("%s ", gact_act_name(p)); 112 + } 113 + 114 + static void flower_print(struct tc_flower_attrs *flower, const char *kind) 115 + { 116 + struct tc_act_attrs *a; 117 + unsigned int i; 118 + 119 + ksft_print_msg("%s:\n", kind); 120 + 121 + if (flower->_present.key_vlan_id) 122 + ksft_print_msg(" vlan_id: %u\n", flower->key_vlan_id); 123 + if (flower->_present.key_vlan_prio) 124 + ksft_print_msg(" vlan_prio: %u\n", flower->key_vlan_prio); 125 + if (flower->_present.key_num_of_vlans) 126 + ksft_print_msg(" num_of_vlans: %u\n", 127 + flower->key_num_of_vlans); 128 + 129 + for (i = 0; i < flower->_count.act; i++) { 130 + a = &flower->act[i]; 131 + ksft_print_msg("action order: %i %s ", i + 1, a->kind); 132 + if (a->options._present.vlan) 133 + print_vlan(&a->options.vlan); 134 + else if (a->options._present.gact) 135 + print_gact(&a->options.gact); 136 + printf("\n"); 137 + } 138 + } 139 + 140 + static void tc_filter_print(struct __test_metadata *_metadata, 141 + struct tc_gettfilter_rsp *f) 142 + { 143 + struct tc_options_msg *opt = &f->options; 144 + 145 + if (opt->_present.flower) { 146 + EXPECT_TRUE((bool)f->_len.kind); 147 + flower_print(&opt->flower, f->kind); 148 + } else if (f->_len.kind) { 149 + ksft_print_msg("%s pref %u proto: %#x\n", f->kind, 150 + (f->_hdr.tcm_info >> 16), 151 + ntohs(TC_H_MIN(f->_hdr.tcm_info))); 152 + } 153 + } 154 + 155 + static int tc_clsact_add(struct ynl_sock *ys, int ifi) 156 + { 157 + struct tc_newqdisc_req *req; 158 + int ret; 159 + 160 + req = tc_newqdisc_req_alloc(); 161 + if (!req) 162 + return -1; 163 + memset(req, 0, sizeof(*req)); 164 + 165 + req->_hdr.tcm_ifindex = ifi; 166 + req->_hdr.tcm_parent = TC_H_CLSACT; 167 + req->_hdr.tcm_handle = TC_HANDLE; 168 + tc_newqdisc_req_set_nlflags(req, 169 + NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE); 170 + tc_newqdisc_req_set_kind(req, "clsact"); 171 + 172 + ret = tc_newqdisc(ys, req); 173 + tc_newqdisc_req_free(req); 174 + 175 + return ret; 176 + } 177 + 178 + static int tc_clsact_del(struct ynl_sock *ys, int ifi) 179 + { 180 + struct tc_delqdisc_req *req; 181 + int ret; 182 + 183 + req = tc_delqdisc_req_alloc(); 184 + if (!req) 185 + return -1; 186 + memset(req, 0, sizeof(*req)); 187 + 188 + req->_hdr.tcm_ifindex = ifi; 189 + req->_hdr.tcm_parent = TC_H_CLSACT; 190 + req->_hdr.tcm_handle = TC_HANDLE; 191 + tc_delqdisc_req_set_nlflags(req, NLM_F_REQUEST); 192 + 193 + ret = tc_delqdisc(ys, req); 194 + tc_delqdisc_req_free(req); 195 + 196 + return ret; 197 + } 198 + 199 + static int tc_filter_add(struct ynl_sock *ys, int ifi) 200 + { 201 + struct tc_newtfilter_req *req; 202 + struct tc_act_attrs *acts; 203 + struct tc_vlan p = { 204 + .action = TC_ACT_PIPE, 205 + .v_action = TCA_VLAN_ACT_PUSH 206 + }; 207 + int ret; 208 + 209 + req = tc_newtfilter_req_alloc(); 210 + if (!req) 211 + return -1; 212 + memset(req, 0, sizeof(*req)); 213 + 214 + acts = tc_act_attrs_alloc(3); 215 + if (!acts) { 216 + tc_newtfilter_req_free(req); 217 + return -1; 218 + } 219 + memset(acts, 0, sizeof(*acts) * 3); 220 + 221 + req->_hdr.tcm_ifindex = ifi; 222 + req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 223 + req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q)); 224 + req->chain = 0; 225 + 226 + tc_newtfilter_req_set_nlflags(req, NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE); 227 + tc_newtfilter_req_set_kind(req, "flower"); 228 + tc_newtfilter_req_set_options_flower_key_vlan_id(req, 100); 229 + tc_newtfilter_req_set_options_flower_key_vlan_prio(req, 5); 230 + tc_newtfilter_req_set_options_flower_key_num_of_vlans(req, 3); 231 + 232 + __tc_newtfilter_req_set_options_flower_act(req, acts, 3); 233 + 234 + /* Skip action at index 0 because in TC, the action array 235 + * index starts at 1, with each index defining the action's 236 + * order. In contrast, in YNL indexed arrays start at index 0. 237 + */ 238 + tc_act_attrs_set_kind(&acts[1], "vlan"); 239 + tc_act_attrs_set_options_vlan_parms(&acts[1], &p, sizeof(p)); 240 + tc_act_attrs_set_options_vlan_push_vlan_id(&acts[1], 200); 241 + tc_act_attrs_set_kind(&acts[2], "vlan"); 242 + tc_act_attrs_set_options_vlan_parms(&acts[2], &p, sizeof(p)); 243 + tc_act_attrs_set_options_vlan_push_vlan_id(&acts[2], 300); 244 + 245 + tc_newtfilter_req_set_options_flower_flags(req, 0); 246 + tc_newtfilter_req_set_options_flower_key_eth_type(req, htons(0x8100)); 247 + 248 + ret = tc_newtfilter(ys, req); 249 + tc_newtfilter_req_free(req); 250 + 251 + return ret; 252 + } 253 + 254 + static int tc_filter_del(struct ynl_sock *ys, int ifi) 255 + { 256 + struct tc_deltfilter_req *req; 257 + int ret; 258 + 259 + req = tc_deltfilter_req_alloc(); 260 + if (!req) 261 + return -1; 262 + memset(req, 0, sizeof(*req)); 263 + 264 + req->_hdr.tcm_ifindex = ifi; 265 + req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 266 + req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q)); 267 + tc_deltfilter_req_set_nlflags(req, NLM_F_REQUEST); 268 + 269 + ret = tc_deltfilter(ys, req); 270 + tc_deltfilter_req_free(req); 271 + 272 + return ret; 273 + } 274 + 275 + FIXTURE(tc) 276 + { 277 + struct ynl_sock *ys; 278 + int ifindex; 279 + }; 280 + 281 + FIXTURE_SETUP(tc) 282 + { 283 + struct ynl_error yerr; 284 + int ret; 285 + 286 + ret = unshare(CLONE_NEWNET); 287 + ASSERT_EQ(0, ret); 288 + 289 + self->ifindex = 1; /* loopback */ 290 + 291 + self->ys = ynl_sock_create(&ynl_tc_family, &yerr); 292 + ASSERT_NE(NULL, self->ys) { 293 + TH_LOG("failed to create tc socket: %s", yerr.msg); 294 + } 295 + } 296 + 297 + FIXTURE_TEARDOWN(tc) 298 + { 299 + ynl_sock_destroy(self->ys); 300 + } 301 + 302 + TEST_F(tc, qdisc) 303 + { 304 + struct tc_getqdisc_req_dump *dreq; 305 + struct tc_newqdisc_req *add_req; 306 + struct tc_delqdisc_req *del_req; 307 + struct tc_getqdisc_list *rsp; 308 + bool found = false; 309 + int ret; 310 + 311 + add_req = tc_newqdisc_req_alloc(); 312 + ASSERT_NE(NULL, add_req); 313 + memset(add_req, 0, sizeof(*add_req)); 314 + 315 + add_req->_hdr.tcm_ifindex = self->ifindex; 316 + add_req->_hdr.tcm_parent = TC_H_ROOT; 317 + tc_newqdisc_req_set_nlflags(add_req, 318 + NLM_F_REQUEST | NLM_F_CREATE); 319 + tc_newqdisc_req_set_kind(add_req, "fq_codel"); 320 + 321 + ret = tc_newqdisc(self->ys, add_req); 322 + tc_newqdisc_req_free(add_req); 323 + ASSERT_EQ(0, ret) { 324 + TH_LOG("qdisc add failed: %s", self->ys->err.msg); 325 + } 326 + 327 + dreq = tc_getqdisc_req_dump_alloc(); 328 + ASSERT_NE(NULL, dreq); 329 + rsp = tc_getqdisc_dump(self->ys, dreq); 330 + tc_getqdisc_req_dump_free(dreq); 331 + ASSERT_NE(NULL, rsp) { 332 + TH_LOG("dump failed: %s", self->ys->err.msg); 333 + } 334 + ASSERT_FALSE(ynl_dump_empty(rsp)); 335 + 336 + ynl_dump_foreach(rsp, qdisc) { 337 + found |= tc_qdisc_print(_metadata, qdisc); 338 + } 339 + tc_getqdisc_list_free(rsp); 340 + EXPECT_TRUE(found); 341 + 342 + del_req = tc_delqdisc_req_alloc(); 343 + ASSERT_NE(NULL, del_req); 344 + memset(del_req, 0, sizeof(*del_req)); 345 + 346 + del_req->_hdr.tcm_ifindex = self->ifindex; 347 + del_req->_hdr.tcm_parent = TC_H_ROOT; 348 + tc_delqdisc_req_set_nlflags(del_req, NLM_F_REQUEST); 349 + 350 + ret = tc_delqdisc(self->ys, del_req); 351 + tc_delqdisc_req_free(del_req); 352 + EXPECT_EQ(0, ret) { 353 + TH_LOG("qdisc del failed: %s", self->ys->err.msg); 354 + } 355 + } 356 + 357 + TEST_F(tc, flower) 358 + { 359 + struct tc_gettfilter_req_dump *dreq; 360 + struct tc_gettfilter_list *rsp; 361 + bool found = false; 362 + int ret; 363 + 364 + ret = tc_clsact_add(self->ys, self->ifindex); 365 + if (ret) 366 + SKIP(return, "clsact not supported: %s", self->ys->err.msg); 367 + 368 + ret = tc_filter_add(self->ys, self->ifindex); 369 + ASSERT_EQ(0, ret) { 370 + TH_LOG("filter add failed: %s", self->ys->err.msg); 371 + } 372 + 373 + dreq = tc_gettfilter_req_dump_alloc(); 374 + ASSERT_NE(NULL, dreq); 375 + memset(dreq, 0, sizeof(*dreq)); 376 + dreq->_hdr.tcm_ifindex = self->ifindex; 377 + dreq->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 378 + dreq->_present.chain = 1; 379 + dreq->chain = 0; 380 + 381 + rsp = tc_gettfilter_dump(self->ys, dreq); 382 + tc_gettfilter_req_dump_free(dreq); 383 + ASSERT_NE(NULL, rsp) { 384 + TH_LOG("filter dump failed: %s", self->ys->err.msg); 385 + } 386 + 387 + ynl_dump_foreach(rsp, flt) { 388 + tc_filter_print(_metadata, flt); 389 + if (flt->options._present.flower) { 390 + EXPECT_EQ(100, flt->options.flower.key_vlan_id); 391 + EXPECT_EQ(5, flt->options.flower.key_vlan_prio); 392 + found = true; 393 + } 394 + } 395 + tc_gettfilter_list_free(rsp); 396 + EXPECT_TRUE(found); 397 + 398 + ret = tc_filter_del(self->ys, self->ifindex); 399 + EXPECT_EQ(0, ret) { 400 + TH_LOG("filter del failed: %s", self->ys->err.msg); 401 + } 402 + 403 + ret = tc_clsact_del(self->ys, self->ifindex); 404 + EXPECT_EQ(0, ret) { 405 + TH_LOG("clsact del failed: %s", self->ys->err.msg); 406 + } 407 + } 408 + 409 + TEST_HARNESS_MAIN
+35
tools/net/ynl/tests/ynl_nsim_lib.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Shared netdevsim setup/cleanup for YNL C test wrappers 4 + 5 + NSIM_ID="1337" 6 + NSIM_DEV="" 7 + KSFT_SKIP=4 8 + 9 + nsim_cleanup() { 10 + echo "$NSIM_ID" > /sys/bus/netdevsim/del_device 2>/dev/null || true 11 + } 12 + 13 + nsim_setup() { 14 + modprobe netdevsim 2>/dev/null 15 + if ! [ -f /sys/bus/netdevsim/new_device ]; then 16 + echo "netdevsim module not available, skipping" >&2 17 + exit "$KSFT_SKIP" 18 + fi 19 + 20 + trap nsim_cleanup EXIT 21 + 22 + echo "$NSIM_ID 1" > /sys/bus/netdevsim/new_device 23 + udevadm settle 24 + 25 + NSIM_DEV=$(ls /sys/bus/netdevsim/devices/netdevsim${NSIM_ID}/net 2>/dev/null | head -1) 26 + if [ -z "$NSIM_DEV" ]; then 27 + echo "failed to find netdevsim device" >&2 28 + exit 1 29 + fi 30 + 31 + ip link set dev "$NSIM_DEV" name nsim0 32 + ip link set dev nsim0 up 33 + ip addr add 192.168.1.1/24 dev nsim0 34 + ip addr add 2001:db8::1/64 dev nsim0 nodad 35 + }