// SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include #include "rt-link-user.h" static void rt_link_print(struct rt_link_getlink_rsp *r) { unsigned int i; printf("%3d: ", r->_hdr.ifi_index); if (r->_len.ifname) printf("%16s: ", r->ifname); if (r->_present.mtu) printf("mtu %5d ", r->mtu); if (r->linkinfo._len.kind) printf("kind %-8s ", r->linkinfo.kind); else printf(" %8s ", ""); if (r->prop_list._count.alt_ifname) { printf("altname "); for (i = 0; i < r->prop_list._count.alt_ifname; i++) printf("%s ", r->prop_list.alt_ifname[i]->str); printf(" "); } if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) { struct rt_link_linkinfo_netkit_attrs *netkit; const char *name; netkit = &r->linkinfo.data.netkit; printf("primary %d ", netkit->primary); name = NULL; if (netkit->_present.policy) name = rt_link_netkit_policy_str(netkit->policy); if (name) printf("policy %s ", name); } printf("\n"); } static int rt_link_create_netkit(struct ynl_sock *ys) { struct rt_link_getlink_ntf *ntf_gl; struct rt_link_newlink_req *req; struct ynl_ntf_base_type *ntf; int ret; req = rt_link_newlink_req_alloc(); if (!req) { fprintf(stderr, "Can't alloc req\n"); return -1; } /* rtnetlink doesn't provide info about the created object. * It expects us to set the ECHO flag and the dig the info out * of the notifications... */ rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); /* Test error messages */ rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10); ret = rt_link_newlink(ys, req); if (ret) { printf("Testing error message for policy being bad:\n\t%s\n", ys->err.msg); } else { fprintf(stderr, "Warning: unexpected success creating netkit with bad attrs\n"); goto created; } rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP); ret = rt_link_newlink(ys, req); created: rt_link_newlink_req_free(req); if (ret) { fprintf(stderr, "YNL: %s\n", ys->err.msg); return -1; } if (!ynl_has_ntf(ys)) { fprintf(stderr, "Warning: interface created but received no notification, won't delete the interface\n"); return 0; } ntf = ynl_ntf_dequeue(ys); if (ntf->cmd != RTM_NEWLINK) { fprintf(stderr, "Warning: unexpected notification type, won't delete the interface\n"); return 0; } ntf_gl = (void *)ntf; ret = ntf_gl->obj._hdr.ifi_index; ynl_ntf_free(ntf); return ret; } static void rt_link_del(struct ynl_sock *ys, int ifindex) { struct rt_link_dellink_req *req; req = rt_link_dellink_req_alloc(); if (!req) { fprintf(stderr, "Can't alloc req\n"); return; } req->_hdr.ifi_index = ifindex; if (rt_link_dellink(ys, req)) fprintf(stderr, "YNL: %s\n", ys->err.msg); else fprintf(stderr, "Trying to delete a Netkit interface (ifindex %d)\n", ifindex); rt_link_dellink_req_free(req); } int main(int argc, char **argv) { struct rt_link_getlink_req_dump *req; struct rt_link_getlink_list *rsp; struct ynl_error yerr; struct ynl_sock *ys; int created = 0; ys = ynl_sock_create(&ynl_rt_link_family, &yerr); if (!ys) { fprintf(stderr, "YNL: %s\n", yerr.msg); return 1; } if (argc > 1) { fprintf(stderr, "Trying to create a Netkit interface\n"); created = rt_link_create_netkit(ys); if (created < 0) goto err_destroy; } req = rt_link_getlink_req_dump_alloc(); if (!req) goto err_del_ifc; rsp = rt_link_getlink_dump(ys, req); rt_link_getlink_req_dump_free(req); if (!rsp) goto err_close; if (ynl_dump_empty(rsp)) fprintf(stderr, "Error: no links reported\n"); ynl_dump_foreach(rsp, link) rt_link_print(link); rt_link_getlink_list_free(rsp); if (created) rt_link_del(ys, created); ynl_sock_destroy(ys); return 0; err_close: fprintf(stderr, "YNL: %s\n", ys->err.msg); err_del_ifc: if (created) rt_link_del(ys, created); err_destroy: ynl_sock_destroy(ys); return 2; }