Merge branch 'dev_walk' into iproute2-next
Serhey Popovych says:
====================
In this seris I replace /proc/net/dev and /sys/class/net usage for walk
through network device list in iptunnel/ip6tunnel and iptuntap with
netlink dump.
Following changed since RFC was sent:
1) Treat @struct rtnl_link_stats and @struct rtnl_link_stats64 as
array with __u32 and __u64 elements respectively in
copy_rtnl_link_stats64() as suggested by Stephen Hemminger.
2) Remove @name and @size parameters from @struct tnl_print_nlmsg_info
since we can get them easily from other data.
Testing.
========
Following script is used to ensure I didn't broke things too much:
\#!/bin/bash
iproute2_dir="$1"
iface='gre1'
pushd "$iproute2_dir" &>/dev/null
for i in new old; do
DIR="/tmp/$i"
mkdir -p "$DIR"
ln -snf ip.$i ip/ip
for o in '' -s -d; do
ip/ip $o tunnel show >"$DIR/ip${o}-tunnel-show"
ip/ip -4 $o tunnel show >"$DIR/ip-4${o}-tunnel-show"
ip/ip -6 $o tunnel show >"$DIR/ip-6${o}-tunnel-show"
ip/ip $o tunnel show dev "$iface" \
>"$DIR/ip${o}-tunnel-show-$iface"
ip/ip $o tuntap show >"$DIR/ip${o}-tuntap-show"
done
done
rm -f ip/ip
diff -urN /tmp/{old,new} |sed -n -Ee'/^(-{3}|\+{3})[[:space:]]+/!p'
rc=$?
popd &>/dev/null
exit $rc
Results:
========
...
fopen /sys/class/net/ipip1/tun_flags: No such file or directory
fopen /sys/class/net/ipip2/tun_flags: No such file or directory
fopen /sys/class/net/gre10/tun_flags: No such file or directory
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note that this comes from ip.old
...
diff -urN /tmp/old/ip-d-tuntap-show /tmp/new/ip-d-tuntap-show
@@ -1,4 +1,4 @@
-tun1: tap user 1004 group 27
- Attached to processes:
tun0: tun user 1000 group 27
Attached to processes:
+tun1: tap user 1004 group 27
+ Attached to processes:
diff -urN /tmp/old/ip-s-tuntap-show /tmp/new/ip-s-tuntap-show
@@ -1,2 +1,2 @@
-tun1: tap user 1004 group 27
tun0: tun user 1000 group 27
+tun1: tap user 1004 group 27
diff -urN /tmp/old/ip-tuntap-show /tmp/new/ip-tuntap-show
@@ -1,2 +1,2 @@
-tun1: tap user 1004 group 27
tun0: tun user 1000 group 27
+tun1: tap user 1004 group 27
So basically only print order for ip tuntap get changes. Rest is intact.
====================
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
commit
58cf7b6759
|
|
@ -284,6 +284,9 @@ int make_path(const char *path, mode_t mode);
|
|||
char *find_cgroup2_mount(void);
|
||||
int get_command_name(const char *pid, char *comm, size_t len);
|
||||
|
||||
int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
|
||||
struct rtattr *tb[]);
|
||||
|
||||
#ifdef NEED_STRLCPY
|
||||
size_t strlcpy(char *dst, const char *src, size_t size);
|
||||
size_t strlcat(char *dst, const char *src, size_t size);
|
||||
|
|
|
|||
115
ip/ip6tunnel.c
115
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,90 +348,33 @@ 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;
|
||||
}
|
||||
if (type != ARPHRD_TUNNEL6 && type != ARPHRD_IP6GRE)
|
||||
continue;
|
||||
ip6_tnl_parm_init(&p1, 0);
|
||||
if (type == ARPHRD_IP6GRE)
|
||||
p1.proto = IPPROTO_GRE;
|
||||
strcpy(p1.name, name);
|
||||
p1.link = ll_name_to_index(p1.name);
|
||||
if (p1.link == 0)
|
||||
continue;
|
||||
if (tnl_get_ioctl(p1.name, &p1))
|
||||
continue;
|
||||
if (!ip6_tnl_parm_match(p, &p1))
|
||||
continue;
|
||||
print_tunnel(&p1);
|
||||
if (show_stats)
|
||||
tnl_print_stats(ptr);
|
||||
printf("\n");
|
||||
}
|
||||
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)
|
||||
do_tunnels_list(&p);
|
||||
else {
|
||||
if (tnl_get_ioctl(p.name, &p))
|
||||
return -1;
|
||||
print_tunnel(&p);
|
||||
printf("\n");
|
||||
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;
|
||||
|
||||
print_tunnel(&p);
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
189
ip/ipaddress.c
189
ip/ipaddress.c
|
|
@ -593,11 +593,18 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
|
|||
}
|
||||
}
|
||||
|
||||
static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
|
||||
const struct rtattr *carrier_changes)
|
||||
static void __print_link_stats(FILE *fp, struct rtattr *tb[])
|
||||
{
|
||||
const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
|
||||
struct rtnl_link_stats64 _s, *s = &_s;
|
||||
int ret;
|
||||
|
||||
ret = get_rtnl_link_stats_rta(s, tb);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
if (is_json_context()) {
|
||||
open_json_object("stats64");
|
||||
open_json_object((ret == sizeof(*s)) ? "stats64" : "stats");
|
||||
|
||||
/* RX stats */
|
||||
open_json_object("rx");
|
||||
|
|
@ -609,8 +616,7 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
|
|||
print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
|
||||
if (s->rx_compressed)
|
||||
print_uint(PRINT_JSON,
|
||||
"compressed",
|
||||
NULL, s->rx_compressed);
|
||||
"compressed", NULL, s->rx_compressed);
|
||||
|
||||
/* RX error stats */
|
||||
if (show_stats > 1) {
|
||||
|
|
@ -647,8 +653,7 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
|
|||
print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
|
||||
if (s->tx_compressed)
|
||||
print_uint(PRINT_JSON,
|
||||
"compressed",
|
||||
NULL, s->tx_compressed);
|
||||
"compressed", NULL, s->tx_compressed);
|
||||
|
||||
/* TX error stats */
|
||||
if (show_stats > 1) {
|
||||
|
|
@ -668,154 +673,6 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
|
|||
print_uint(PRINT_JSON, "carrier_changes", NULL,
|
||||
rta_getattr_u32(carrier_changes));
|
||||
}
|
||||
close_json_object();
|
||||
close_json_object();
|
||||
|
||||
} else {
|
||||
/* RX stats */
|
||||
fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
|
||||
s->rx_compressed ? "compressed" : "", _SL_);
|
||||
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, s->rx_bytes);
|
||||
print_num(fp, 8, s->rx_packets);
|
||||
print_num(fp, 7, s->rx_errors);
|
||||
print_num(fp, 7, s->rx_dropped);
|
||||
print_num(fp, 7, s->rx_over_errors);
|
||||
print_num(fp, 7, s->multicast);
|
||||
if (s->rx_compressed)
|
||||
print_num(fp, 7, s->rx_compressed);
|
||||
|
||||
/* RX error stats */
|
||||
if (show_stats > 1) {
|
||||
fprintf(fp, "%s", _SL_);
|
||||
fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
|
||||
s->rx_nohandler ? " nohandler" : "", _SL_);
|
||||
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 8, s->rx_length_errors);
|
||||
print_num(fp, 7, s->rx_crc_errors);
|
||||
print_num(fp, 7, s->rx_frame_errors);
|
||||
print_num(fp, 7, s->rx_fifo_errors);
|
||||
print_num(fp, 7, s->rx_missed_errors);
|
||||
if (s->rx_nohandler)
|
||||
print_num(fp, 7, s->rx_nohandler);
|
||||
|
||||
}
|
||||
fprintf(fp, "%s", _SL_);
|
||||
|
||||
/* TX stats */
|
||||
fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
|
||||
s->tx_compressed ? "compressed" : "", _SL_);
|
||||
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, s->tx_bytes);
|
||||
print_num(fp, 8, s->tx_packets);
|
||||
print_num(fp, 7, s->tx_errors);
|
||||
print_num(fp, 7, s->tx_dropped);
|
||||
print_num(fp, 7, s->tx_carrier_errors);
|
||||
print_num(fp, 7, s->collisions);
|
||||
if (s->tx_compressed)
|
||||
print_num(fp, 7, s->tx_compressed);
|
||||
|
||||
/* TX error stats */
|
||||
if (show_stats > 1) {
|
||||
fprintf(fp, "%s", _SL_);
|
||||
fprintf(fp, " TX errors: aborted fifo window heartbeat");
|
||||
if (carrier_changes)
|
||||
fprintf(fp, " transns");
|
||||
fprintf(fp, "%s", _SL_);
|
||||
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 8, s->tx_aborted_errors);
|
||||
print_num(fp, 7, s->tx_fifo_errors);
|
||||
print_num(fp, 7, s->tx_window_errors);
|
||||
print_num(fp, 7, s->tx_heartbeat_errors);
|
||||
if (carrier_changes)
|
||||
print_num(fp, 7,
|
||||
rta_getattr_u32(carrier_changes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
|
||||
const struct rtattr *carrier_changes)
|
||||
{
|
||||
if (is_json_context()) {
|
||||
open_json_object("stats");
|
||||
|
||||
/* RX stats */
|
||||
open_json_object("rx");
|
||||
print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes);
|
||||
print_uint(PRINT_JSON, "packets", NULL, s->rx_packets);
|
||||
print_uint(PRINT_JSON, "errors", NULL, s->rx_errors);
|
||||
print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped);
|
||||
print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors);
|
||||
print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
|
||||
if (s->rx_compressed)
|
||||
print_int(PRINT_JSON,
|
||||
"compressed",
|
||||
NULL, s->rx_compressed);
|
||||
|
||||
/* RX error stats */
|
||||
if (show_stats > 1) {
|
||||
print_uint(PRINT_JSON,
|
||||
"length_errors",
|
||||
NULL, s->rx_length_errors);
|
||||
print_uint(PRINT_JSON,
|
||||
"crc_errors",
|
||||
NULL, s->rx_crc_errors);
|
||||
print_uint(PRINT_JSON,
|
||||
"frame_errors",
|
||||
NULL, s->rx_frame_errors);
|
||||
print_uint(PRINT_JSON,
|
||||
"fifo_errors",
|
||||
NULL, s->rx_fifo_errors);
|
||||
print_uint(PRINT_JSON,
|
||||
"missed_errors",
|
||||
NULL, s->rx_missed_errors);
|
||||
if (s->rx_nohandler)
|
||||
print_int(PRINT_JSON,
|
||||
"nohandler",
|
||||
NULL, s->rx_nohandler);
|
||||
}
|
||||
close_json_object();
|
||||
|
||||
/* TX stats */
|
||||
open_json_object("tx");
|
||||
print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes);
|
||||
print_uint(PRINT_JSON, "packets", NULL, s->tx_packets);
|
||||
print_uint(PRINT_JSON, "errors", NULL, s->tx_errors);
|
||||
print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped);
|
||||
print_uint(PRINT_JSON,
|
||||
"carrier_errors",
|
||||
NULL, s->tx_carrier_errors);
|
||||
print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
|
||||
if (s->tx_compressed)
|
||||
print_int(PRINT_JSON,
|
||||
"compressed",
|
||||
NULL, s->tx_compressed);
|
||||
|
||||
/* TX error stats */
|
||||
if (show_stats > 1) {
|
||||
print_uint(PRINT_JSON,
|
||||
"aborted_errors",
|
||||
NULL, s->tx_aborted_errors);
|
||||
print_uint(PRINT_JSON,
|
||||
"fifo_errors",
|
||||
NULL, s->tx_fifo_errors);
|
||||
print_uint(PRINT_JSON,
|
||||
"window_errors",
|
||||
NULL, s->tx_window_errors);
|
||||
print_uint(PRINT_JSON,
|
||||
"heartbeat_errors",
|
||||
NULL, s->tx_heartbeat_errors);
|
||||
if (carrier_changes)
|
||||
print_uint(PRINT_JSON,
|
||||
"carrier_changes",
|
||||
NULL,
|
||||
rta_getattr_u32(carrier_changes));
|
||||
}
|
||||
|
||||
close_json_object();
|
||||
close_json_object();
|
||||
|
|
@ -824,7 +681,6 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
|
|||
fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
|
||||
s->rx_compressed ? "compressed" : "", _SL_);
|
||||
|
||||
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, s->rx_bytes);
|
||||
print_num(fp, 8, s->rx_packets);
|
||||
|
|
@ -885,27 +741,6 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
|
|||
}
|
||||
}
|
||||
|
||||
static void __print_link_stats(FILE *fp, struct rtattr **tb)
|
||||
{
|
||||
const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
|
||||
|
||||
if (tb[IFLA_STATS64]) {
|
||||
struct rtnl_link_stats64 stats = { 0 };
|
||||
|
||||
memcpy(&stats, RTA_DATA(tb[IFLA_STATS64]),
|
||||
MIN(RTA_PAYLOAD(tb[IFLA_STATS64]), sizeof(stats)));
|
||||
|
||||
print_link_stats64(fp, &stats, carrier_changes);
|
||||
} else if (tb[IFLA_STATS]) {
|
||||
struct rtnl_link_stats stats = { 0 };
|
||||
|
||||
memcpy(&stats, RTA_DATA(tb[IFLA_STATS]),
|
||||
MIN(RTA_PAYLOAD(tb[IFLA_STATS]), sizeof(stats)));
|
||||
|
||||
print_link_stats32(fp, &stats, carrier_changes);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_link_stats(FILE *fp, struct nlmsghdr *n)
|
||||
{
|
||||
struct ifinfomsg *ifi = NLMSG_DATA(n);
|
||||
|
|
|
|||
|
|
@ -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,86 +374,52 @@ static void print_tunnel(struct ip_tunnel_parm *p)
|
|||
printf("%s Checksum output packets.", _SL_);
|
||||
}
|
||||
|
||||
static int do_tunnels_list(struct ip_tunnel_parm *p)
|
||||
|
||||
static void ip_tunnel_parm_initialize(const struct tnl_print_nlmsg_info *info)
|
||||
{
|
||||
char buf[512];
|
||||
int err = -1;
|
||||
FILE *fp = fopen("/proc/net/dev", "r");
|
||||
struct ip_tunnel_parm *p2 = info->p2;
|
||||
|
||||
if (fp == NULL) {
|
||||
perror("fopen");
|
||||
return -1;
|
||||
}
|
||||
memset(p2, 0, sizeof(*p2));
|
||||
}
|
||||
|
||||
/* skip header lines */
|
||||
if (!fgets(buf, sizeof(buf), fp) ||
|
||||
!fgets(buf, sizeof(buf), fp)) {
|
||||
fprintf(stderr, "/proc/net/dev read error\n");
|
||||
goto end;
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
|
||||
continue;
|
||||
if (tnl_get_ioctl(name, &p1))
|
||||
continue;
|
||||
if ((p->link && p1.link != p->link) ||
|
||||
(p->name[0] && strcmp(p1.name, p->name)) ||
|
||||
(p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
|
||||
(p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
|
||||
(p->i_key && p1.i_key != p->i_key))
|
||||
continue;
|
||||
print_tunnel(&p1);
|
||||
if (show_stats)
|
||||
tnl_print_stats(ptr);
|
||||
printf("\n");
|
||||
}
|
||||
err = 0;
|
||||
end:
|
||||
fclose(fp);
|
||||
return err;
|
||||
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) &&
|
||||
(!p1->iph.saddr || p1->iph.saddr == p2->iph.saddr) &&
|
||||
(!p1->i_key || p1->i_key == p2->i_key));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
print_tunnel(&p);
|
||||
printf("\n");
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
121
ip/iptuntap.c
121
ip/iptuntap.c
|
|
@ -20,6 +20,7 @@
|
|||
#include <sys/ioctl.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -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;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_show(int argc, char **argv)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
long flags, owner = -1, group = -1;
|
||||
|
||||
dir = opendir("/sys/class/net");
|
||||
if (!dir) {
|
||||
perror("opendir");
|
||||
if (rtnl_wilddump_req_filter_fn(&rth, AF_UNSPEC, RTM_GETLINK,
|
||||
tuntap_filter_req) < 0) {
|
||||
perror("Cannot send dump request\n");
|
||||
return -1;
|
||||
}
|
||||
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");
|
||||
}
|
||||
if (rtnl_dump_filter(&rth, print_tuntap, NULL) < 0) {
|
||||
fprintf(stderr, "Dump terminated\n");
|
||||
return -1;
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
114
ip/tunnel.c
114
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,30 +308,99 @@ void tnl_print_endpoint(const char *name, const struct rtattr *rta, int family)
|
|||
}
|
||||
}
|
||||
|
||||
/* tnl_print_stats - print tunnel statistics
|
||||
*
|
||||
* @buf - tunnel interface's line in /proc/net/dev,
|
||||
* starting past the interface name and following colon
|
||||
*/
|
||||
void tnl_print_stats(const char *buf)
|
||||
static void tnl_print_stats(const struct rtnl_link_stats64 *s)
|
||||
{
|
||||
unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
|
||||
rx_fifo, rx_frame,
|
||||
tx_bytes, tx_packets, tx_errs, tx_drops,
|
||||
tx_fifo, tx_colls, tx_carrier, rx_multi;
|
||||
|
||||
if (sscanf(buf, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",
|
||||
&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;
|
||||
|
||||
printf("%s", _SL_);
|
||||
printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
|
||||
printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
|
||||
rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
|
||||
printf(" %-10lld %-12lld %-6lld %-8lld %-8lld %-8lld%s",
|
||||
s->rx_packets, s->rx_bytes, s->rx_errors, s->rx_frame_errors,
|
||||
s->rx_fifo_errors, s->multicast, _SL_);
|
||||
printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_);
|
||||
printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
|
||||
tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
|
||||
printf(" %-10lld %-12lld %-6lld %-8lld %-8lld %-6lld",
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
17
ip/tunnel.h
17
ip/tunnel.h
|
|
@ -21,9 +21,25 @@
|
|||
#ifndef __TUNNEL_H__
|
||||
#define __TUNNEL_H__ 1
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct rtattr;
|
||||
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);
|
||||
|
||||
|
|
@ -39,6 +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 char *buf);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
45
lib/utils.c
45
lib/utils.c
|
|
@ -1431,6 +1431,51 @@ int get_real_family(int rtm_type, int rtm_family)
|
|||
return rtm_family;
|
||||
}
|
||||
|
||||
/* Based on copy_rtnl_link_stats() from kernel at net/core/rtnetlink.c */
|
||||
static void copy_rtnl_link_stats64(struct rtnl_link_stats64 *stats64,
|
||||
const struct rtnl_link_stats *stats)
|
||||
{
|
||||
__u64 *a = (__u64 *)stats64;
|
||||
const __u32 *b = (const __u32 *)stats;
|
||||
const __u32 *e = b + sizeof(*stats) / sizeof(*b);
|
||||
|
||||
while (b < e)
|
||||
*a++ = *b++;
|
||||
}
|
||||
|
||||
int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
|
||||
struct rtattr *tb[])
|
||||
{
|
||||
struct rtnl_link_stats stats;
|
||||
void *s;
|
||||
struct rtattr *rta;
|
||||
int size, len;
|
||||
|
||||
if (tb[IFLA_STATS64]) {
|
||||
rta = tb[IFLA_STATS64];
|
||||
size = sizeof(struct rtnl_link_stats64);
|
||||
s = stats64;
|
||||
} else if (tb[IFLA_STATS]) {
|
||||
rta = tb[IFLA_STATS];
|
||||
size = sizeof(struct rtnl_link_stats);
|
||||
s = &stats;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = RTA_PAYLOAD(rta);
|
||||
if (len < size)
|
||||
memset(s + len, 0, size - len);
|
||||
else
|
||||
len = size;
|
||||
|
||||
memcpy(s, RTA_DATA(rta), len);
|
||||
|
||||
if (s != stats64)
|
||||
copy_rtnl_link_stats64(stats64, s);
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef NEED_STRLCPY
|
||||
size_t strlcpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue