busybox/networking/libiproute/iptunnel.c

573 lines
15 KiB
C
Raw Normal View History

/* vi: set sw=4 ts=4: */
/*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* Changes:
*
* Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
* Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit
* Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag
*/
2002-12-16 13:07:21 +05:30
#include <netinet/ip.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <asm/types.h>
#ifndef __constant_htons
#define __constant_htons htons
#endif
// FYI: #define SIOCDEVPRIVATE 0x89F0
/* From linux/if_tunnel.h. #including it proved troublesome
* (redefiniton errors due to name collisions in linux/ and net[inet]/) */
#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2)
#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3)
//#define SIOCGETPRL (SIOCDEVPRIVATE + 4)
//#define SIOCADDPRL (SIOCDEVPRIVATE + 5)
//#define SIOCDELPRL (SIOCDEVPRIVATE + 6)
//#define SIOCCHGPRL (SIOCDEVPRIVATE + 7)
#define GRE_CSUM __constant_htons(0x8000)
//#define GRE_ROUTING __constant_htons(0x4000)
#define GRE_KEY __constant_htons(0x2000)
#define GRE_SEQ __constant_htons(0x1000)
//#define GRE_STRICT __constant_htons(0x0800)
//#define GRE_REC __constant_htons(0x0700)
//#define GRE_FLAGS __constant_htons(0x00F8)
//#define GRE_VERSION __constant_htons(0x0007)
struct ip_tunnel_parm {
char name[IFNAMSIZ];
int link;
uint16_t i_flags;
uint16_t o_flags;
uint32_t i_key;
uint32_t o_key;
struct iphdr iph;
};
/* SIT-mode i_flags */
//#define SIT_ISATAP 0x0001
//struct ip_tunnel_prl {
// uint32_t addr;
// uint16_t flags;
// uint16_t __reserved;
// uint32_t datalen;
// uint32_t __reserved2;
// /* data follows */
//};
///* PRL flags */
//#define PRL_DEFAULT 0x0001
2007-06-01 04:12:12 +05:30
#include "ip_common.h" /* #include "libbb.h" is inside */
#include "rt_names.h"
#include "utils.h"
/* Dies on error */
static int do_ioctl_get_ifindex(char *dev)
{
struct ifreq ifr;
int fd;
strncpy_IFNAMSIZ(ifr.ifr_name, dev);
fd = xsocket(AF_INET, SOCK_DGRAM, 0);
xioctl(fd, SIOCGIFINDEX, &ifr);
close(fd);
return ifr.ifr_ifindex;
}
static int do_ioctl_get_iftype(char *dev)
{
struct ifreq ifr;
int fd;
int err;
strncpy_IFNAMSIZ(ifr.ifr_name, dev);
fd = xsocket(AF_INET, SOCK_DGRAM, 0);
err = ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr);
close(fd);
return err ? -1 : ifr.ifr_addr.sa_family;
}
2002-11-28 17:49:51 +05:30
static char *do_ioctl_get_ifname(int idx)
{
struct ifreq ifr;
int fd;
int err;
ifr.ifr_ifindex = idx;
fd = xsocket(AF_INET, SOCK_DGRAM, 0);
err = ioctl_or_warn(fd, SIOCGIFNAME, &ifr);
close(fd);
return err ? NULL : xstrndup(ifr.ifr_name, sizeof(ifr.ifr_name));
}
static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
{
struct ifreq ifr;
int fd;
int err;
strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
ifr.ifr_ifru.ifru_data = (void*)p;
fd = xsocket(AF_INET, SOCK_DGRAM, 0);
err = ioctl_or_warn(fd, SIOCGETTUNNEL, &ifr);
close(fd);
return err;
}
/* Dies on error, otherwise returns 0 */
static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
{
struct ifreq ifr;
int fd;
2002-11-28 17:49:51 +05:30
if (cmd == SIOCCHGTUNNEL && p->name[0]) {
strncpy_IFNAMSIZ(ifr.ifr_name, p->name);
2002-11-28 17:49:51 +05:30
} else {
strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
2002-11-28 17:49:51 +05:30
}
ifr.ifr_ifru.ifru_data = (void*)p;
fd = xsocket(AF_INET, SOCK_DGRAM, 0);
#if ENABLE_IOCTL_HEX2STR_ERROR
/* #define magic will turn ioctl# into string */
if (cmd == SIOCCHGTUNNEL)
xioctl(fd, SIOCCHGTUNNEL, &ifr);
else
xioctl(fd, SIOCADDTUNNEL, &ifr);
#else
xioctl(fd, cmd, &ifr);
#endif
close(fd);
return 0;
}
/* Dies on error, otherwise returns 0 */
static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
{
struct ifreq ifr;
int fd;
2002-11-28 17:49:51 +05:30
if (p->name[0]) {
strncpy_IFNAMSIZ(ifr.ifr_name, p->name);
2002-11-28 17:49:51 +05:30
} else {
strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
2002-11-28 17:49:51 +05:30
}
ifr.ifr_ifru.ifru_data = (void*)p;
fd = xsocket(AF_INET, SOCK_DGRAM, 0);
xioctl(fd, SIOCDELTUNNEL, &ifr);
close(fd);
return 0;
}
/* Dies on error */
static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p)
{
static const char keywords[] ALIGN1 =
"mode\0""ipip\0""ip/ip\0""gre\0""gre/ip\0""sit\0""ipv6/ip\0"
"key\0""ikey\0""okey\0""seq\0""iseq\0""oseq\0"
"csum\0""icsum\0""ocsum\0""nopmtudisc\0""pmtudisc\0"
"remote\0""any\0""local\0""dev\0"
"ttl\0""inherit\0""tos\0""dsfield\0"
"name\0";
enum {
ARG_mode, ARG_ipip, ARG_ip_ip, ARG_gre, ARG_gre_ip, ARG_sit, ARG_ip6_ip,
ARG_key, ARG_ikey, ARG_okey, ARG_seq, ARG_iseq, ARG_oseq,
ARG_csum, ARG_icsum, ARG_ocsum, ARG_nopmtudisc, ARG_pmtudisc,
ARG_remote, ARG_any, ARG_local, ARG_dev,
ARG_ttl, ARG_inherit, ARG_tos, ARG_dsfield,
ARG_name
};
int count = 0;
char medium[IFNAMSIZ];
int key;
memset(p, 0, sizeof(*p));
medium[0] = '\0';
p->iph.version = 4;
p->iph.ihl = 5;
#ifndef IP_DF
#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
#endif
p->iph.frag_off = htons(IP_DF);
while (*argv) {
key = index_in_strings(keywords, *argv);
if (key == ARG_mode) {
NEXT_ARG();
key = index_in_strings(keywords, *argv);
if (key == ARG_ipip ||
key == ARG_ip_ip
) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
2008-10-30 23:12:49 +05:30
bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
}
p->iph.protocol = IPPROTO_IPIP;
} else if (key == ARG_gre ||
key == ARG_gre_ip
) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
2008-10-30 23:12:49 +05:30
bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
}
p->iph.protocol = IPPROTO_GRE;
} else if (key == ARG_sit ||
key == ARG_ip6_ip
) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
2008-10-30 23:12:49 +05:30
bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
}
p->iph.protocol = IPPROTO_IPV6;
} else {
bb_error_msg_and_die("%s tunnel mode", "can't guess");
}
} else if (key == ARG_key) {
unsigned uval;
NEXT_ARG();
p->i_flags |= GRE_KEY;
p->o_flags |= GRE_KEY;
if (strchr(*argv, '.'))
p->i_key = p->o_key = get_addr32(*argv);
else {
uval = get_unsigned(*argv, "key");
p->i_key = p->o_key = htonl(uval);
}
} else if (key == ARG_ikey) {
unsigned uval;
NEXT_ARG();
p->i_flags |= GRE_KEY;
if (strchr(*argv, '.'))
p->o_key = get_addr32(*argv);
else {
uval = get_unsigned(*argv, "ikey");
p->i_key = htonl(uval);
}
} else if (key == ARG_okey) {
unsigned uval;
NEXT_ARG();
p->o_flags |= GRE_KEY;
if (strchr(*argv, '.'))
p->o_key = get_addr32(*argv);
else {
uval = get_unsigned(*argv, "okey");
p->o_key = htonl(uval);
}
} else if (key == ARG_seq) {
p->i_flags |= GRE_SEQ;
p->o_flags |= GRE_SEQ;
} else if (key == ARG_iseq) {
p->i_flags |= GRE_SEQ;
} else if (key == ARG_oseq) {
p->o_flags |= GRE_SEQ;
} else if (key == ARG_csum) {
p->i_flags |= GRE_CSUM;
p->o_flags |= GRE_CSUM;
} else if (key == ARG_icsum) {
p->i_flags |= GRE_CSUM;
} else if (key == ARG_ocsum) {
p->o_flags |= GRE_CSUM;
} else if (key == ARG_nopmtudisc) {
p->iph.frag_off = 0;
} else if (key == ARG_pmtudisc) {
p->iph.frag_off = htons(IP_DF);
} else if (key == ARG_remote) {
NEXT_ARG();
key = index_in_strings(keywords, *argv);
if (key != ARG_any)
p->iph.daddr = get_addr32(*argv);
} else if (key == ARG_local) {
NEXT_ARG();
key = index_in_strings(keywords, *argv);
if (key != ARG_any)
p->iph.saddr = get_addr32(*argv);
} else if (key == ARG_dev) {
NEXT_ARG();
strncpy_IFNAMSIZ(medium, *argv);
} else if (key == ARG_ttl) {
unsigned uval;
NEXT_ARG();
key = index_in_strings(keywords, *argv);
if (key != ARG_inherit) {
uval = get_unsigned(*argv, "TTL");
if (uval > 255)
invarg_1_to_2(*argv, "TTL");
p->iph.ttl = uval;
}
} else if (key == ARG_tos ||
key == ARG_dsfield
) {
uint32_t uval;
NEXT_ARG();
key = index_in_strings(keywords, *argv);
if (key != ARG_inherit) {
if (rtnl_dsfield_a2n(&uval, *argv))
invarg_1_to_2(*argv, "TOS");
p->iph.tos = uval;
} else
p->iph.tos = 1;
} else {
if (key == ARG_name) {
NEXT_ARG();
}
if (p->name[0])
duparg2("name", *argv);
strncpy_IFNAMSIZ(p->name, *argv);
if (cmd == SIOCCHGTUNNEL && count == 0) {
struct ip_tunnel_parm old_p;
memset(&old_p, 0, sizeof(old_p));
if (do_get_ioctl(*argv, &old_p))
exit(EXIT_FAILURE);
*p = old_p;
}
}
count++;
argv++;
}
if (p->iph.protocol == 0) {
if (memcmp(p->name, "gre", 3) == 0)
p->iph.protocol = IPPROTO_GRE;
else if (memcmp(p->name, "ipip", 4) == 0)
p->iph.protocol = IPPROTO_IPIP;
else if (memcmp(p->name, "sit", 3) == 0)
p->iph.protocol = IPPROTO_IPV6;
}
if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg_and_die("keys are not allowed with ipip and sit");
}
}
if (medium[0]) {
p->link = do_ioctl_get_ifindex(medium);
}
if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
p->i_key = p->iph.daddr;
p->i_flags |= GRE_KEY;
}
if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
p->o_key = p->iph.daddr;
p->o_flags |= GRE_KEY;
}
if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg_and_die("broadcast tunnel requires a source address");
}
}
/* Return value becomes exitcode. It's okay to not return at all */
static int do_add(int cmd, char **argv)
{
struct ip_tunnel_parm p;
parse_args(argv, cmd, &p);
if (p.iph.ttl && p.iph.frag_off == 0) {
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg_and_die("ttl != 0 and noptmudisc are incompatible");
}
switch (p.iph.protocol) {
case IPPROTO_IPIP:
return do_add_ioctl(cmd, "tunl0", &p);
case IPPROTO_GRE:
return do_add_ioctl(cmd, "gre0", &p);
case IPPROTO_IPV6:
return do_add_ioctl(cmd, "sit0", &p);
default:
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg_and_die("can't determine tunnel mode (ipip, gre or sit)");
}
}
/* Return value becomes exitcode. It's okay to not return at all */
static int do_del(char **argv)
{
struct ip_tunnel_parm p;
parse_args(argv, SIOCDELTUNNEL, &p);
switch (p.iph.protocol) {
case IPPROTO_IPIP:
return do_del_ioctl("tunl0", &p);
case IPPROTO_GRE:
return do_del_ioctl("gre0", &p);
case IPPROTO_IPV6:
return do_del_ioctl("sit0", &p);
default:
return do_del_ioctl(p.name, &p);
}
}
static void print_tunnel(struct ip_tunnel_parm *p)
{
char s3[INET_ADDRSTRLEN];
char s4[INET_ADDRSTRLEN];
printf("%s: %s/ip remote %s local %s ",
p->name,
p->iph.protocol == IPPROTO_IPIP ? "ip" :
p->iph.protocol == IPPROTO_GRE ? "gre" :
p->iph.protocol == IPPROTO_IPV6 ? "ipv6" :
"unknown",
p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr) : "any",
p->iph.saddr ? format_host(AF_INET, 4, &p->iph.saddr) : "any"
);
if (p->link) {
char *n = do_ioctl_get_ifname(p->link);
if (n) {
printf(" dev %s ", n);
free(n);
}
}
if (p->iph.ttl)
printf(" ttl %d ", p->iph.ttl);
else
printf(" ttl inherit ");
if (p->iph.tos) {
printf(" tos");
if (p->iph.tos & 1)
printf(" inherit");
if (p->iph.tos & ~1)
printf("%c%s ", p->iph.tos & 1 ? '/' : ' ',
rtnl_dsfield_n2a(p->iph.tos & ~1));
}
if (!(p->iph.frag_off & htons(IP_DF)))
printf(" nopmtudisc");
inet_ntop(AF_INET, &p->i_key, s3, sizeof(s3));
inet_ntop(AF_INET, &p->o_key, s4, sizeof(s4));
if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key)
printf(" key %s", s3);
else {
if (p->i_flags & GRE_KEY)
printf(" ikey %s ", s3);
if (p->o_flags & GRE_KEY)
printf(" okey %s ", s4);
}
if (p->i_flags & GRE_SEQ)
printf("%c Drop packets out of sequence.\n", _SL_);
if (p->i_flags & GRE_CSUM)
printf("%c Checksum in received packet is required.", _SL_);
if (p->o_flags & GRE_SEQ)
printf("%c Sequence packets on output.", _SL_);
if (p->o_flags & GRE_CSUM)
printf("%c Checksum output packets.", _SL_);
}
static void do_tunnels_list(struct ip_tunnel_parm *p)
{
char name[IFNAMSIZ];
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;
int type;
struct ip_tunnel_parm p1;
char buf[512];
FILE *fp = fopen_or_warn("/proc/net/dev", "r");
if (fp == NULL) {
return;
}
2008-10-30 23:12:49 +05:30
/* skip headers */
fgets(buf, sizeof(buf), fp);
fgets(buf, sizeof(buf), fp);
while (fgets(buf, sizeof(buf), fp) != NULL) {
char *ptr;
/*buf[sizeof(buf) - 1] = 0; - fgets is safe anyway */
ptr = strchr(buf, ':');
if (ptr == NULL ||
(*ptr++ = 0, sscanf(buf, "%s", name) != 1)
) {
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg("wrong format of /proc/net/dev");
return;
}
if (sscanf(ptr, "%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)
continue;
if (p->name[0] && strcmp(p->name, name))
continue;
type = do_ioctl_get_iftype(name);
if (type == -1) {
bb_error_msg("can't get type of [%s]", name);
continue;
}
if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
continue;
memset(&p1, 0, sizeof(p1));
if (do_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);
bb_putchar('\n');
}
}
/* Return value becomes exitcode. It's okay to not return at all */
static int do_show(char **argv)
{
int err;
struct ip_tunnel_parm p;
parse_args(argv, SIOCGETTUNNEL, &p);
switch (p.iph.protocol) {
case IPPROTO_IPIP:
err = do_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
break;
case IPPROTO_GRE:
err = do_get_ioctl(p.name[0] ? p.name : "gre0", &p);
break;
case IPPROTO_IPV6:
err = do_get_ioctl(p.name[0] ? p.name : "sit0", &p);
break;
default:
do_tunnels_list(&p);
return 0;
}
if (err)
return -1;
print_tunnel(&p);
bb_putchar('\n');
return 0;
}
/* Return value becomes exitcode. It's okay to not return at all */
int FAST_FUNC do_iptunnel(char **argv)
{
static const char keywords[] ALIGN1 =
"add\0""change\0""delete\0""show\0""list\0""lst\0";
enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst };
if (*argv) {
int key = index_in_substrings(keywords, *argv);
if (key < 0)
invarg_1_to_2(*argv, applet_name);
argv++;
if (key == ARG_add)
return do_add(SIOCADDTUNNEL, argv);
if (key == ARG_change)
return do_add(SIOCCHGTUNNEL, argv);
if (key == ARG_del)
return do_del(argv);
}
return do_show(argv);
}