From mboxrd@z Thu Jan 1 00:00:00 1970 From: Serhey Popovych Subject: [RFC][PATCH iproute2-next 6/6] tuntap: Use netlink to walk through tuntap list Date: Thu, 1 Feb 2018 21:40:58 +0200 Message-ID: <1517514058-23596-7-git-send-email-serhe.popovych@gmail.com> References: <1517514058-23596-1-git-send-email-serhe.popovych@gmail.com> To: netdev@vger.kernel.org Return-path: Received: from mail-lf0-f68.google.com ([209.85.215.68]:34206 "EHLO mail-lf0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754746AbeBATl1 (ORCPT ); Thu, 1 Feb 2018 14:41:27 -0500 Received: by mail-lf0-f68.google.com with SMTP id k19so28029551lfj.1 for ; Thu, 01 Feb 2018 11:41:26 -0800 (PST) Received: from tuxracer.localdomain ([2a01:6d80::195:20:96:53]) by smtp.gmail.com with ESMTPSA id v197sm57571lfa.25.2018.02.01.11.41.24 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 01 Feb 2018 11:41:24 -0800 (PST) In-Reply-To: <1517514058-23596-1-git-send-email-serhe.popovych@gmail.com> Sender: netdev-owner@vger.kernel.org List-ID: It seems bad idea to depend on sysfs being mounted and reflected to the current network namespace. Same applies to procfs. Instead netlink should be used to talk to the kernel and get list of specific network devices among with their parameters. Support for kernel netlink message filtering by passing IFLA_INFO_KIND in RTM_GETLINK request: if kernel does not support filtering by the kind we will check it in reply anyway. Check for ifi->ifi_type to be either ARPHRD_NONE or ARPHRD_ETHER to seed up things a bit without kernel level filtering. Unfortunately tun driver does not implement dumping it's configuration via netlink and we still need to use read_prop() which depends on sysfs to get additional tun device information. Signed-off-by: Serhey Popovych --- ip/iptuntap.c | 121 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 30 deletions(-) diff --git a/ip/iptuntap.c b/ip/iptuntap.c index 09f2be2..4628db2 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,8 @@ #include "utils.h" #include "ip_common.h" +static const char drv_name[] = "tun"; + #define TUNDEV "/dev/net/tun" static void usage(void) __attribute__((noreturn)); @@ -348,43 +351,101 @@ next: globfree(&globbuf); } +static int tuntap_filter_req(struct nlmsghdr *nlh, int reqlen) +{ + struct rtattr *linkinfo; + int err; -static int do_show(int argc, char **argv) + linkinfo = addattr_nest(nlh, reqlen, IFLA_LINKINFO); + + err = addattr_l(nlh, reqlen, IFLA_INFO_KIND, + drv_name, sizeof(drv_name) - 1); + if (err) + return err; + + addattr_nest_end(nlh, linkinfo); + + return 0; +} + +static int print_tuntap(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) { - DIR *dir; - struct dirent *d; + struct ifinfomsg *ifi = NLMSG_DATA(n); + struct rtattr *tb[IFLA_MAX+1]; + struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + const char *name, *kind; long flags, owner = -1, group = -1; - dir = opendir("/sys/class/net"); - if (!dir) { - perror("opendir"); + if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) + return 0; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi))) return -1; + + switch (ifi->ifi_type) { + case ARPHRD_NONE: + case ARPHRD_ETHER: + break; + default: + return 0; } - while ((d = readdir(dir))) { - if (d->d_name[0] == '.' && - (d->d_name[1] == 0 || d->d_name[1] == '.')) - continue; - - if (read_prop(d->d_name, "tun_flags", &flags)) - continue; - - read_prop(d->d_name, "owner", &owner); - read_prop(d->d_name, "group", &group); - - printf("%s:", d->d_name); - print_flags(flags); - if (owner != -1) - printf(" user %ld", owner); - if (group != -1) - printf(" group %ld", group); - printf("\n"); - if (show_details) { - printf("\tAttached to processes:"); - show_processes(d->d_name); - printf("\n"); - } + + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); + + if (!tb[IFLA_IFNAME]) + return 0; + + if (!tb[IFLA_LINKINFO]) + return 0; + + parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); + + if (!linkinfo[IFLA_INFO_KIND]) + return 0; + + kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]); + if (strcmp(kind, drv_name)) + return 0; + + name = rta_getattr_str(tb[IFLA_IFNAME]); + + if (read_prop(name, "tun_flags", &flags)) + return 0; + if (read_prop(name, "owner", &owner)) + return 0; + if (read_prop(name, "group", &group)) + return 0; + + printf("%s:", name); + print_flags(flags); + if (owner != -1) + printf(" user %ld", owner); + if (group != -1) + printf(" group %ld", group); + fputc('\n', stdout); + if (show_details) { + printf("\tAttached to processes:"); + show_processes(name); + fputc('\n', stdout); } - closedir(dir); + + return 0; +} + +static int do_show(int argc, char **argv) +{ + if (rtnl_wilddump_req_filter_fn(&rth, AF_UNSPEC, RTM_GETLINK, + tuntap_filter_req) < 0) { + perror("Cannot send dump request\n"); + return -1; + } + + if (rtnl_dump_filter(&rth, print_tuntap, NULL) < 0) { + fprintf(stderr, "Dump terminated\n"); + return -1; + } + return 0; } -- 1.7.10.4