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