From: Serhey Popovych <serhe.popovych@gmail.com>
To: netdev@vger.kernel.org
Subject: [PATCH iproute2-next v2 5/6] iptunnel/ip6tunnel: Use netlink to walk through tunnels list
Date: Wed, 7 Feb 2018 08:30:55 +0200 [thread overview]
Message-ID: <1517985056-10043-6-git-send-email-serhe.popovych@gmail.com> (raw)
In-Reply-To: <1517985056-10043-1-git-send-email-serhe.popovych@gmail.com>
Both tunnels use legacy /proc/net/dev interface to get tunnel device and
it's statistics. This may cause problems for cases when procfs either
not mounted or not unshare(2)d for given network namespace.
Use netlink to walk through list of tunnel devices which is network
namespace aware and provides additional information such as statistics
in the dump message.
Since both address family specific variants of do_tunnels_list() nearly
the same, except for tunnel parameters structure initialization,
matching and printing we can introduce common one in tunnel.c.
To implement address family specific parts introduce new data structure
@struct tnl_print_nlmsg_info what contains all necessary information as
well as pointers to ->init(), ->match() and ->print() callbacks.
Annotate data structures by const where appropriate.
Signed-off-by: Serhey Popovych <serhe.popovych@gmail.com>
---
ip/ip6tunnel.c | 114 +++++++++++++++---------------------------------------
ip/iptunnel.c | 106 +++++++++++++-------------------------------------
ip/tunnel.c | 117 +++++++++++++++++++++++++++++++++++++++++---------------
ip/tunnel.h | 20 ++++++++--
4 files changed, 159 insertions(+), 198 deletions(-)
diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c
index 2e6f513..c7fa082 100644
--- a/ip/ip6tunnel.c
+++ b/ip/ip6tunnel.c
@@ -67,8 +67,9 @@ static void usage(void)
exit(-1);
}
-static void print_tunnel(struct ip6_tnl_parm2 *p)
+static void print_tunnel(const void *t)
{
+ const struct ip6_tnl_parm2 *p = t;
char s1[1024];
char s2[1024];
@@ -313,13 +314,24 @@ static void ip6_tnl_parm_init(struct ip6_tnl_parm2 *p, int apply_default)
}
}
-/*
- * @p1: user specified parameter
- * @p2: database entry
- */
-static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1,
- const struct ip6_tnl_parm2 *p2)
+static void ip6_tnl_parm_initialize(const struct tnl_print_nlmsg_info *info)
+{
+ const struct ifinfomsg *ifi = info->ifi;
+ const struct ip6_tnl_parm2 *p1 = info->p1;
+ struct ip6_tnl_parm2 *p2 = info->p2;
+
+ ip6_tnl_parm_init(p2, 0);
+ if (ifi->ifi_type == ARPHRD_IP6GRE)
+ p2->proto = IPPROTO_GRE;
+ p2->link = ifi->ifi_index;
+ strcpy(p2->name, p1->name);
+}
+
+static bool ip6_tnl_parm_match(const struct tnl_print_nlmsg_info *info)
{
+ const struct ip6_tnl_parm2 *p1 = info->p1;
+ const struct ip6_tnl_parm2 *p2 = info->p2;
+
return ((!p1->link || p1->link == p2->link) &&
(!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
(IN6_IS_ADDR_UNSPECIFIED(&p1->laddr) ||
@@ -336,91 +348,27 @@ static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1,
(!p1->flags || (p1->flags & p2->flags)));
}
-static int do_tunnels_list(struct ip6_tnl_parm2 *p)
-{
- char buf[512];
- int err = -1;
- FILE *fp = fopen("/proc/net/dev", "r");
-
- if (fp == NULL) {
- perror("fopen");
- return -1;
- }
-
- /* skip two lines at the begenning of the file */
- if (!fgets(buf, sizeof(buf), fp) ||
- !fgets(buf, sizeof(buf), fp)) {
- fprintf(stderr, "/proc/net/dev read error\n");
- goto end;
- }
-
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- char name[IFNAMSIZ];
- int index, type;
- struct ip6_tnl_parm2 p1;
- char *ptr;
-
- buf[sizeof(buf) - 1] = '\0';
- ptr = strchr(buf, ':');
- if (ptr == NULL ||
- (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
- fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n");
- goto end;
- }
- if (p->name[0] && strcmp(p->name, name))
- continue;
- index = ll_name_to_index(name);
- if (index == 0)
- continue;
- type = ll_index_to_type(index);
- if (type == -1) {
- fprintf(stderr, "Failed to get type of \"%s\"\n", name);
- continue;
- }
- switch (type) {
- case ARPHRD_TUNNEL6:
- case ARPHRD_IP6GRE:
- break;
- default:
- continue;
- }
- ip6_tnl_parm_init(&p1, 0);
- if (type == ARPHRD_IP6GRE)
- p1.proto = IPPROTO_GRE;
- p1.link = index;
- strcpy(p1.name, name);
- if (tnl_get_ioctl(name, &p1))
- continue;
- if (!ip6_tnl_parm_match(p, &p1))
- continue;
- print_tunnel(&p1);
- if (show_stats) {
- struct rtnl_link_stats64 s;
-
- if (!tnl_get_stats(ptr, &s))
- tnl_print_stats(&s);
- }
- fputc('\n', stdout);
- }
- err = 0;
- end:
- fclose(fp);
- return err;
-}
-
static int do_show(int argc, char **argv)
{
- struct ip6_tnl_parm2 p;
+ struct ip6_tnl_parm2 p, p1;
- ll_init_map(&rth);
ip6_tnl_parm_init(&p, 0);
p.proto = 0; /* default to any */
if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
return -1;
- if (!p.name[0] || show_stats)
- return do_tunnels_list(&p);
+ if (!p.name[0] || show_stats) {
+ struct tnl_print_nlmsg_info info = {
+ .p1 = &p,
+ .p2 = &p1,
+ .init = ip6_tnl_parm_initialize,
+ .match = ip6_tnl_parm_match,
+ .print = print_tunnel,
+ };
+
+ return do_tunnels_list(&info);
+ }
if (tnl_get_ioctl(p.name, &p))
return -1;
diff --git a/ip/iptunnel.c b/ip/iptunnel.c
index ff201a7..1f04f95 100644
--- a/ip/iptunnel.c
+++ b/ip/iptunnel.c
@@ -286,8 +286,9 @@ static int do_del(int argc, char **argv)
return tnl_del_ioctl(tnl_defname(&p) ? : p.name, p.name, &p);
}
-static void print_tunnel(struct ip_tunnel_parm *p)
+static void print_tunnel(const void *t)
{
+ const struct ip_tunnel_parm *p = t;
struct ip_tunnel_6rd ip6rd = {};
char s1[1024];
char s2[1024];
@@ -373,13 +374,19 @@ static void print_tunnel(struct ip_tunnel_parm *p)
printf("%s Checksum output packets.", _SL_);
}
-/*
- * @p1: user specified parameter
- * @p2: database entry
- */
-static int ip_tunnel_parm_match(const struct ip_tunnel_parm *p1,
- const struct ip_tunnel_parm *p2)
+
+static void ip_tunnel_parm_initialize(const struct tnl_print_nlmsg_info *info)
+{
+ struct ip_tunnel_parm *p2 = info->p2;
+
+ memset(p2, 0, sizeof(*p2));
+}
+
+static bool ip_tunnel_parm_match(const struct tnl_print_nlmsg_info *info)
{
+ const struct ip_tunnel_parm *p1 = info->p1;
+ const struct ip_tunnel_parm *p2 = info->p2;
+
return ((!p1->link || p1->link == p2->link) &&
(!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
(!p1->iph.daddr || p1->iph.daddr == p2->iph.daddr) &&
@@ -387,87 +394,26 @@ static int ip_tunnel_parm_match(const struct ip_tunnel_parm *p1,
(!p1->i_key || p1->i_key == p2->i_key));
}
-static int do_tunnels_list(struct ip_tunnel_parm *p)
-{
- char buf[512];
- int err = -1;
- FILE *fp = fopen("/proc/net/dev", "r");
-
- if (fp == NULL) {
- perror("fopen");
- return -1;
- }
-
- /* skip two lines at the begenning of the file */
- if (!fgets(buf, sizeof(buf), fp) ||
- !fgets(buf, sizeof(buf), fp)) {
- fprintf(stderr, "/proc/net/dev read error\n");
- goto end;
- }
-
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- char name[IFNAMSIZ];
- int index, type;
- struct ip_tunnel_parm p1;
- char *ptr;
-
- buf[sizeof(buf) - 1] = '\0';
- ptr = strchr(buf, ':');
- if (ptr == NULL ||
- (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
- fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n");
- goto end;
- }
- if (p->name[0] && strcmp(p->name, name))
- continue;
- index = ll_name_to_index(name);
- if (index == 0)
- continue;
- type = ll_index_to_type(index);
- if (type == -1) {
- fprintf(stderr, "Failed to get type of \"%s\"\n", name);
- continue;
- }
- switch (type) {
- case ARPHRD_TUNNEL:
- case ARPHRD_IPGRE:
- case ARPHRD_SIT:
- break;
- default:
- continue;
- }
- memset(&p1, 0, sizeof(p1));
- if (tnl_get_ioctl(name, &p1))
- continue;
- if (!ip_tunnel_parm_match(p, &p1))
- continue;
- print_tunnel(&p1);
- if (show_stats) {
- struct rtnl_link_stats64 s;
-
- if (!tnl_get_stats(ptr, &s))
- tnl_print_stats(&s);
- }
- fputc('\n', stdout);
- }
- err = 0;
- end:
- fclose(fp);
- return err;
-}
-
static int do_show(int argc, char **argv)
{
- struct ip_tunnel_parm p;
+ struct ip_tunnel_parm p, p1;
const char *basedev;
- ll_init_map(&rth);
if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
return -1;
basedev = tnl_defname(&p);
- if (!basedev)
- return do_tunnels_list(&p);
+ if (!basedev) {
+ struct tnl_print_nlmsg_info info = {
+ .p1 = &p,
+ .p2 = &p1,
+ .init = ip_tunnel_parm_initialize,
+ .match = ip_tunnel_parm_match,
+ .print = print_tunnel,
+ };
+
+ return do_tunnels_list(&info);
+ }
if (tnl_get_ioctl(p.name[0] ? p.name : basedev, &p))
return -1;
diff --git a/ip/tunnel.c b/ip/tunnel.c
index 06533cf..7030995 100644
--- a/ip/tunnel.c
+++ b/ip/tunnel.c
@@ -33,6 +33,7 @@
#include <linux/if.h>
#include <linux/ip.h>
#include <linux/if_tunnel.h>
+#include <linux/if_arp.h>
#include "utils.h"
#include "tunnel.h"
@@ -307,37 +308,7 @@ void tnl_print_endpoint(const char *name, const struct rtattr *rta, int family)
}
}
-int tnl_get_stats(const char *buf, struct rtnl_link_stats64 *s)
-{
- /* rx */
- __u64 *rx_bytes = &s->rx_bytes;
- __u64 *rx_packets = &s->rx_packets;
- __u64 *rx_errs = &s->rx_errors;
- __u64 *rx_drops = &s->rx_dropped;
- __u64 *rx_fifo = &s->rx_fifo_errors;
- __u64 *rx_frame = &s->rx_frame_errors;
- __u64 *rx_multi = &s->multicast;
- /* tx */
- __u64 *tx_bytes = &s->tx_bytes;
- __u64 *tx_packets = &s->tx_packets;
- __u64 *tx_errs = &s->tx_errors;
- __u64 *tx_drops = &s->tx_dropped;
- __u64 *tx_fifo = &s->tx_fifo_errors;
- __u64 *tx_carrier = &s->tx_carrier_errors;
- __u64 *tx_colls = &s->collisions;
-
- if (sscanf(buf,
- "%llu%llu%llu%llu%llu%llu%llu%*d%llu%llu%llu%llu%llu%llu%llu",
- rx_bytes, rx_packets, rx_errs, rx_drops,
- rx_fifo, rx_frame, rx_multi,
- tx_bytes, tx_packets, tx_errs, tx_drops,
- tx_fifo, tx_colls, tx_carrier) != 14)
- return -1;
-
- return 0;
-}
-
-void tnl_print_stats(const struct rtnl_link_stats64 *s)
+static void tnl_print_stats(const struct rtnl_link_stats64 *s)
{
printf("%s", _SL_);
printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
@@ -349,3 +320,87 @@ void tnl_print_stats(const struct rtnl_link_stats64 *s)
s->tx_packets, s->tx_bytes, s->tx_errors, s->collisions,
s->tx_carrier_errors, s->tx_dropped);
}
+
+static int print_nlmsg_tunnel(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ struct tnl_print_nlmsg_info *info = arg;
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct rtattr *tb[IFLA_MAX+1];
+ const char *name, *n1;
+
+ if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
+ return 0;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi)))
+ return -1;
+
+ if (preferred_family == AF_INET) {
+ switch (ifi->ifi_type) {
+ case ARPHRD_TUNNEL:
+ case ARPHRD_IPGRE:
+ case ARPHRD_SIT:
+ break;
+ default:
+ return 0;
+ }
+ } else {
+ switch (ifi->ifi_type) {
+ case ARPHRD_TUNNEL6:
+ case ARPHRD_IP6GRE:
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
+
+ if (!tb[IFLA_IFNAME])
+ return 0;
+
+ name = rta_getattr_str(tb[IFLA_IFNAME]);
+
+ /* Assume p1->name[IFNAMSIZ] is first field of structure */
+ n1 = info->p1;
+ if (n1[0] && strcmp(n1, name))
+ return 0;
+
+ info->ifi = ifi;
+ info->init(info);
+
+ /* TODO: parse netlink attributes */
+ if (tnl_get_ioctl(name, info->p2))
+ return 0;
+
+ if (!info->match(info))
+ return 0;
+
+ info->print(info->p2);
+ if (show_stats) {
+ struct rtnl_link_stats64 s;
+
+ if (get_rtnl_link_stats_rta(&s, tb) <= 0)
+ return -1;
+
+ tnl_print_stats(&s);
+ }
+ fputc('\n', stdout);
+
+ return 0;
+}
+
+int do_tunnels_list(struct tnl_print_nlmsg_info *info)
+{
+ if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
+ perror("Cannot send dump request\n");
+ return -1;
+ }
+
+ if (rtnl_dump_filter(&rth, print_nlmsg_tunnel, info) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/ip/tunnel.h b/ip/tunnel.h
index 5fe488b..e530d07 100644
--- a/ip/tunnel.h
+++ b/ip/tunnel.h
@@ -21,10 +21,25 @@
#ifndef __TUNNEL_H__
#define __TUNNEL_H__ 1
+#include <stdbool.h>
#include <linux/types.h>
struct rtattr;
-struct rtnl_link_stats64;
+struct ifinfomsg;
+
+extern struct rtnl_handle rth;
+
+struct tnl_print_nlmsg_info {
+ const struct ifinfomsg *ifi;
+ const void *p1;
+ void *p2;
+
+ void (*init)(const struct tnl_print_nlmsg_info *info);
+ bool (*match)(const struct tnl_print_nlmsg_info *info);
+ void (*print)(const void *t);
+};
+
+int do_tunnels_list(struct tnl_print_nlmsg_info *info);
const char *tnl_strproto(__u8 proto);
@@ -40,8 +55,5 @@ void tnl_print_encap(struct rtattr *tb[],
int encap_sport, int encap_dport);
void tnl_print_endpoint(const char *name,
const struct rtattr *rta, int family);
-void tnl_print_stats(const struct rtnl_link_stats64 *s);
-
-int tnl_get_stats(const char *buf, struct rtnl_link_stats64 *s);
#endif
--
1.7.10.4
next prev parent reply other threads:[~2018-02-07 6:31 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-07 6:30 [PATCH iproute2-next v2 0/6] ip: Use netlink to walk through network device list Serhey Popovych
2018-02-07 6:30 ` [PATCH iproute2-next v2 1/6] ipaddress: Unify print_link_stats() and print_link_stats64() Serhey Popovych
2018-02-07 6:30 ` [PATCH iproute2-next v2 2/6] ip: Introduce get_rtnl_link_stats_rta() to get link statistics Serhey Popovych
2018-02-07 6:30 ` [PATCH iproute2-next v2 3/6] tunnel: Split statistic getting and printing Serhey Popovych
2018-02-07 6:30 ` [PATCH iproute2-next v2 4/6] iptunnel/ip6tunnel: Code cleanups Serhey Popovych
2018-02-07 6:30 ` Serhey Popovych [this message]
2018-02-07 6:30 ` [PATCH iproute2-next v2 6/6] tuntap: Use netlink to walk through tuntap list Serhey Popovych
2018-02-08 0:20 ` [PATCH iproute2-next v2 0/6] ip: Use netlink to walk through network device list David Ahern
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1517985056-10043-6-git-send-email-serhe.popovych@gmail.com \
--to=serhe.popovych@gmail.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).