Signed-off-by: Serhey Popovych <serhe.popov...@gmail.com>
---
 ip/ip6tunnel.c |  115 ++++++++++++++++---------------------------------------
 ip/iptunnel.c  |  108 ++++++++++++++-------------------------------------
 ip/tunnel.c    |  117 +++++++++++++++++++++++++++++++++++++++++---------------
 ip/tunnel.h    |   18 +++++++--
 4 files changed, 162 insertions(+), 196 deletions(-)

diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c
index 0e53c23..430cf5d 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(void *t)
 {
+       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 char *name = info->name;
+       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, 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,90 +348,29 @@ 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';
-               if ((ptr = strchr(buf, ':')) == 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,
+                       .name  = p.name,
+                       .size  = sizeof(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 dba5942..2506301 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(void *t)
 {
+       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,28 @@ 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 header lines */
-       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,
+                       .name  = p.name,
+                       .size  = sizeof(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..8da26d9 100644
--- a/ip/tunnel.c
+++ b/ip/tunnel.c
@@ -33,11 +33,14 @@
 #include <linux/if.h>
 #include <linux/ip.h>
 #include <linux/if_tunnel.h>
+#include <linux/if_arp.h>
 
 #include "utils.h"
 #include "tunnel.h"
 #include "json_print.h"
 
+extern struct rtnl_handle rth;
+
 const char *tnl_strproto(__u8 proto)
 {
        switch (proto) {
@@ -307,37 +310,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 +322,85 @@ 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;
+
+       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]);
+
+       if (info->name[0] && strcmp(info->name, 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..e1f3562 100644
--- a/ip/tunnel.h
+++ b/ip/tunnel.h
@@ -21,10 +21,11 @@
 #ifndef __TUNNEL_H__
 #define __TUNNEL_H__ 1
 
+#include <stdbool.h>
 #include <linux/types.h>
 
 struct rtattr;
-struct rtnl_link_stats64;
+struct ifinfomsg;
 
 const char *tnl_strproto(__u8 proto);
 
@@ -40,8 +41,19 @@ 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);
+struct tnl_print_nlmsg_info {
+       const struct ifinfomsg *ifi;
+       const char *name;
+       const void *p1;
+       void *p2;
+       size_t size;
+
+       void (*init)(const struct tnl_print_nlmsg_info *info);
+       bool (*match)(const struct tnl_print_nlmsg_info *info);
+       void (*print)(void *t);
+};
+
+int do_tunnels_list(struct tnl_print_nlmsg_info *info);
 
 #endif
-- 
1.7.10.4

Reply via email to