mirror_iproute2/ip/ipntable.c
Matteo Croce 8589eb4efd treewide: refactor help messages
Every tool in the iproute2 package have one or more function to show
an help message to the user. Some of these functions print the help
line by line with a series of printf call, e.g. ip/xfrm_state.c does
60 fprintf calls.
If we group all the calls to a single one and just concatenate strings,
we save a lot of libc calls and thus object size. The size difference
of the compiled binaries calculated with bloat-o-meter is:

        ip/ip:
        add/remove: 0/0 grow/shrink: 5/15 up/down: 103/-4796 (-4693)
        Total: Before=672591, After=667898, chg -0.70%
        ip/rtmon:
        add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-54 (-54)
        Total: Before=48879, After=48825, chg -0.11%
        tc/tc:
        add/remove: 0/2 grow/shrink: 31/10 up/down: 882/-6133 (-5251)
        Total: Before=351912, After=346661, chg -1.49%
        bridge/bridge:
        add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-459 (-459)
        Total: Before=70502, After=70043, chg -0.65%
        misc/lnstat:
        add/remove: 0/1 grow/shrink: 1/0 up/down: 48/-486 (-438)
        Total: Before=9960, After=9522, chg -4.40%
        tipc/tipc:
        add/remove: 0/0 grow/shrink: 1/1 up/down: 18/-62 (-44)
        Total: Before=79182, After=79138, chg -0.06%

While at it, indent some strings which were starting at column 0,
and use tabs where possible, to have a consistent style across helps.

Signed-off-by: Matteo Croce <mcroce@redhat.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
2019-05-20 14:35:07 -07:00

697 lines
17 KiB
C

/*
* Copyright (C)2006 USAGI/WIDE Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*/
/*
* based on ipneigh.c
*/
/*
* Authors:
* Masahide NAKAMURA @USAGI
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <time.h>
#include "utils.h"
#include "ip_common.h"
#include "json_print.h"
static struct
{
int family;
int index;
#define NONE_DEV (-1)
const char *name;
} filter;
static void usage(void) __attribute__((noreturn));
static void usage(void)
{
fprintf(stderr,
"Usage: ip ntable change name NAME [ dev DEV ]\n"
" [ thresh1 VAL ] [ thresh2 VAL ] [ thresh3 VAL ] [ gc_int MSEC ]\n"
" [ PARMS ]\n"
"Usage: ip ntable show [ dev DEV ] [ name NAME ]\n"
"PARMS := [ base_reachable MSEC ] [ retrans MSEC ] [ gc_stale MSEC ]\n"
" [ delay_probe MSEC ] [ queue LEN ]\n"
" [ app_probes VAL ] [ ucast_probes VAL ] [ mcast_probes VAL ]\n"
" [ anycast_delay MSEC ] [ proxy_delay MSEC ] [ proxy_queue LEN ]\n"
" [ locktime MSEC ]\n"
);
exit(-1);
}
static int ipntable_modify(int cmd, int flags, int argc, char **argv)
{
struct {
struct nlmsghdr n;
struct ndtmsg ndtm;
char buf[1024];
} req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)),
.n.nlmsg_flags = NLM_F_REQUEST | flags,
.n.nlmsg_type = cmd,
.ndtm.ndtm_family = preferred_family,
};
char *namep = NULL;
char *threshsp = NULL;
char *gc_intp = NULL;
char parms_buf[1024] = {};
struct rtattr *parms_rta = (struct rtattr *)parms_buf;
int parms_change = 0;
parms_rta->rta_type = NDTA_PARMS;
parms_rta->rta_len = RTA_LENGTH(0);
while (argc > 0) {
if (strcmp(*argv, "name") == 0) {
int len;
NEXT_ARG();
if (namep)
duparg("NAME", *argv);
namep = *argv;
len = strlen(namep) + 1;
addattr_l(&req.n, sizeof(req), NDTA_NAME, namep, len);
} else if (strcmp(*argv, "thresh1") == 0) {
__u32 thresh1;
NEXT_ARG();
threshsp = *argv;
if (get_u32(&thresh1, *argv, 0))
invarg("\"thresh1\" value is invalid", *argv);
addattr32(&req.n, sizeof(req), NDTA_THRESH1, thresh1);
} else if (strcmp(*argv, "thresh2") == 0) {
__u32 thresh2;
NEXT_ARG();
threshsp = *argv;
if (get_u32(&thresh2, *argv, 0))
invarg("\"thresh2\" value is invalid", *argv);
addattr32(&req.n, sizeof(req), NDTA_THRESH2, thresh2);
} else if (strcmp(*argv, "thresh3") == 0) {
__u32 thresh3;
NEXT_ARG();
threshsp = *argv;
if (get_u32(&thresh3, *argv, 0))
invarg("\"thresh3\" value is invalid", *argv);
addattr32(&req.n, sizeof(req), NDTA_THRESH3, thresh3);
} else if (strcmp(*argv, "gc_int") == 0) {
__u64 gc_int;
NEXT_ARG();
gc_intp = *argv;
if (get_u64(&gc_int, *argv, 0))
invarg("\"gc_int\" value is invalid", *argv);
addattr_l(&req.n, sizeof(req), NDTA_GC_INTERVAL,
&gc_int, sizeof(gc_int));
} else if (strcmp(*argv, "dev") == 0) {
__u32 ifindex;
NEXT_ARG();
ifindex = ll_name_to_index(*argv);
if (!ifindex)
return nodev(*argv);
rta_addattr32(parms_rta, sizeof(parms_buf),
NDTPA_IFINDEX, ifindex);
} else if (strcmp(*argv, "base_reachable") == 0) {
__u64 breachable;
NEXT_ARG();
if (get_u64(&breachable, *argv, 0))
invarg("\"base_reachable\" value is invalid", *argv);
rta_addattr_l(parms_rta, sizeof(parms_buf),
NDTPA_BASE_REACHABLE_TIME,
&breachable, sizeof(breachable));
parms_change = 1;
} else if (strcmp(*argv, "retrans") == 0) {
__u64 retrans;
NEXT_ARG();
if (get_u64(&retrans, *argv, 0))
invarg("\"retrans\" value is invalid", *argv);
rta_addattr_l(parms_rta, sizeof(parms_buf),
NDTPA_RETRANS_TIME,
&retrans, sizeof(retrans));
parms_change = 1;
} else if (strcmp(*argv, "gc_stale") == 0) {
__u64 gc_stale;
NEXT_ARG();
if (get_u64(&gc_stale, *argv, 0))
invarg("\"gc_stale\" value is invalid", *argv);
rta_addattr_l(parms_rta, sizeof(parms_buf),
NDTPA_GC_STALETIME,
&gc_stale, sizeof(gc_stale));
parms_change = 1;
} else if (strcmp(*argv, "delay_probe") == 0) {
__u64 delay_probe;
NEXT_ARG();
if (get_u64(&delay_probe, *argv, 0))
invarg("\"delay_probe\" value is invalid", *argv);
rta_addattr_l(parms_rta, sizeof(parms_buf),
NDTPA_DELAY_PROBE_TIME,
&delay_probe, sizeof(delay_probe));
parms_change = 1;
} else if (strcmp(*argv, "queue") == 0) {
__u32 queue;
NEXT_ARG();
if (get_u32(&queue, *argv, 0))
invarg("\"queue\" value is invalid", *argv);
rta_addattr32(parms_rta, sizeof(parms_buf),
NDTPA_QUEUE_LEN, queue);
parms_change = 1;
} else if (strcmp(*argv, "app_probes") == 0) {
__u32 aprobe;
NEXT_ARG();
if (get_u32(&aprobe, *argv, 0))
invarg("\"app_probes\" value is invalid", *argv);
rta_addattr32(parms_rta, sizeof(parms_buf),
NDTPA_APP_PROBES, aprobe);
parms_change = 1;
} else if (strcmp(*argv, "ucast_probes") == 0) {
__u32 uprobe;
NEXT_ARG();
if (get_u32(&uprobe, *argv, 0))
invarg("\"ucast_probes\" value is invalid", *argv);
rta_addattr32(parms_rta, sizeof(parms_buf),
NDTPA_UCAST_PROBES, uprobe);
parms_change = 1;
} else if (strcmp(*argv, "mcast_probes") == 0) {
__u32 mprobe;
NEXT_ARG();
if (get_u32(&mprobe, *argv, 0))
invarg("\"mcast_probes\" value is invalid", *argv);
rta_addattr32(parms_rta, sizeof(parms_buf),
NDTPA_MCAST_PROBES, mprobe);
parms_change = 1;
} else if (strcmp(*argv, "anycast_delay") == 0) {
__u64 anycast_delay;
NEXT_ARG();
if (get_u64(&anycast_delay, *argv, 0))
invarg("\"anycast_delay\" value is invalid", *argv);
rta_addattr_l(parms_rta, sizeof(parms_buf),
NDTPA_ANYCAST_DELAY,
&anycast_delay, sizeof(anycast_delay));
parms_change = 1;
} else if (strcmp(*argv, "proxy_delay") == 0) {
__u64 proxy_delay;
NEXT_ARG();
if (get_u64(&proxy_delay, *argv, 0))
invarg("\"proxy_delay\" value is invalid", *argv);
rta_addattr_l(parms_rta, sizeof(parms_buf),
NDTPA_PROXY_DELAY,
&proxy_delay, sizeof(proxy_delay));
parms_change = 1;
} else if (strcmp(*argv, "proxy_queue") == 0) {
__u32 pqueue;
NEXT_ARG();
if (get_u32(&pqueue, *argv, 0))
invarg("\"proxy_queue\" value is invalid", *argv);
rta_addattr32(parms_rta, sizeof(parms_buf),
NDTPA_PROXY_QLEN, pqueue);
parms_change = 1;
} else if (strcmp(*argv, "locktime") == 0) {
__u64 locktime;
NEXT_ARG();
if (get_u64(&locktime, *argv, 0))
invarg("\"locktime\" value is invalid", *argv);
rta_addattr_l(parms_rta, sizeof(parms_buf),
NDTPA_LOCKTIME,
&locktime, sizeof(locktime));
parms_change = 1;
} else {
invarg("unknown", *argv);
}
argc--; argv++;
}
if (!namep)
missarg("NAME");
if (!threshsp && !gc_intp && !parms_change) {
fprintf(stderr, "Not enough information: changeable attributes required.\n");
exit(-1);
}
if (parms_rta->rta_len > RTA_LENGTH(0)) {
addattr_l(&req.n, sizeof(req), NDTA_PARMS, RTA_DATA(parms_rta),
RTA_PAYLOAD(parms_rta));
}
if (rtnl_talk(&rth, &req.n, NULL) < 0)
exit(2);
return 0;
}
static const char *ntable_strtime_delta(__u32 msec)
{
static char str[32];
struct timeval now = {};
time_t t;
struct tm *tp;
if (msec == 0)
goto error;
if (gettimeofday(&now, NULL) < 0) {
perror("gettimeofday");
goto error;
}
t = now.tv_sec - (msec / 1000);
tp = localtime(&t);
if (!tp)
goto error;
strftime(str, sizeof(str), "%Y-%m-%d %T", tp);
return str;
error:
strcpy(str, "(error)");
return str;
}
static void print_ndtconfig(const struct ndt_config *ndtc)
{
print_uint(PRINT_ANY, "key_length",
" config key_len %u ", ndtc->ndtc_key_len);
print_uint(PRINT_ANY, "entry_size",
"entry_size %u ", ndtc->ndtc_entry_size);
print_uint(PRINT_ANY, "entries", "entries %u ", ndtc->ndtc_entries);
print_nl();
print_string(PRINT_ANY, "last_flush",
" last_flush %s ",
ntable_strtime_delta(ndtc->ndtc_last_flush));
print_string(PRINT_ANY, "last_rand",
"last_rand %s ",
ntable_strtime_delta(ndtc->ndtc_last_rand));
print_nl();
print_uint(PRINT_ANY, "hash_rnd",
" hash_rnd %u ", ndtc->ndtc_hash_rnd);
print_0xhex(PRINT_ANY, "hash_mask",
"hash_mask %08llx ", ndtc->ndtc_hash_mask);
print_uint(PRINT_ANY, "hash_chain_gc",
"hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
print_uint(PRINT_ANY, "proxy_qlen",
"proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
print_nl();
}
static void print_ndtparams(struct rtattr *tpb[])
{
if (tpb[NDTPA_IFINDEX]) {
__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
print_string(PRINT_FP, NULL, " dev ", NULL);
print_color_string(PRINT_ANY, COLOR_IFNAME,
"dev", "%s ", ll_index_to_name(ifindex));
print_nl();
}
print_string(PRINT_FP, NULL, " ", NULL);
if (tpb[NDTPA_REFCNT]) {
__u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
print_uint(PRINT_ANY, "refcnt", "refcnt %u ", refcnt);
}
if (tpb[NDTPA_REACHABLE_TIME]) {
__u64 reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
print_u64(PRINT_ANY, "reachable",
"reachable %llu ", reachable);
}
if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
__u64 breachable
= rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
print_u64(PRINT_ANY, "base_reachable",
"base_reachable %llu ", breachable);
}
if (tpb[NDTPA_RETRANS_TIME]) {
__u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
print_u64(PRINT_ANY, "retrans", "retrans %llu ", retrans);
}
print_string(PRINT_FP, NULL, "%s ", _SL_);
if (tpb[NDTPA_GC_STALETIME]) {
__u64 gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
print_u64(PRINT_ANY, "gc_stale", "gc_stale %llu ", gc_stale);
}
if (tpb[NDTPA_DELAY_PROBE_TIME]) {
__u64 delay_probe
= rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
print_u64(PRINT_ANY, "delay_probe",
"delay_probe %llu ", delay_probe);
}
if (tpb[NDTPA_QUEUE_LEN]) {
__u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
print_uint(PRINT_ANY, "queue", "queue %u ", queue);
}
print_string(PRINT_FP, NULL, "%s ", _SL_);
if (tpb[NDTPA_APP_PROBES]) {
__u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
print_uint(PRINT_ANY, "app_probes", "app_probes %u ", aprobe);
}
if (tpb[NDTPA_UCAST_PROBES]) {
__u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
print_uint(PRINT_ANY, "ucast_probes",
"ucast_probes %u ", uprobe);
}
if (tpb[NDTPA_MCAST_PROBES]) {
__u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
print_uint(PRINT_ANY, "mcast_probes",
"mcast_probes %u ", mprobe);
}
print_string(PRINT_FP, NULL, "%s ", _SL_);
if (tpb[NDTPA_ANYCAST_DELAY]) {
__u64 anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
print_u64(PRINT_ANY, "anycast_delay",
"anycast_delay %llu ", anycast_delay);
}
if (tpb[NDTPA_PROXY_DELAY]) {
__u64 proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
print_u64(PRINT_ANY, "proxy_delay",
"proxy_delay %llu ", proxy_delay);
}
if (tpb[NDTPA_PROXY_QLEN]) {
__u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
print_uint(PRINT_ANY, "proxy_queue", "proxy_queue %u ", pqueue);
}
if (tpb[NDTPA_LOCKTIME]) {
__u64 locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
print_u64(PRINT_ANY, "locktime", "locktime %llu ", locktime);
}
print_nl();
}
static void print_ndtstats(const struct ndt_stats *ndts)
{
print_string(PRINT_FP, NULL, " stats ", NULL);
print_u64(PRINT_ANY, "allocs", "allocs %llu ", ndts->ndts_allocs);
print_u64(PRINT_ANY, "destroys", "destroys %llu ",
ndts->ndts_destroys);
print_u64(PRINT_ANY, "hash_grows", "hash_grows %llu ",
ndts->ndts_hash_grows);
print_string(PRINT_FP, NULL, "%s ", _SL_);
print_u64(PRINT_ANY, "res_failed", "res_failed %llu ",
ndts->ndts_res_failed);
print_u64(PRINT_ANY, "lookups", "lookups %llu ", ndts->ndts_lookups);
print_u64(PRINT_ANY, "hits", "hits %llu ", ndts->ndts_hits);
print_string(PRINT_FP, NULL, "%s ", _SL_);
print_u64(PRINT_ANY, "rcv_probes_mcast", "rcv_probes_mcast %llu ",
ndts->ndts_rcv_probes_mcast);
print_u64(PRINT_ANY, "rcv_probes_ucast", "rcv_probes_ucast %llu ",
ndts->ndts_rcv_probes_ucast);
print_string(PRINT_FP, NULL, "%s ", _SL_);
print_u64(PRINT_ANY, "periodic_gc_runs", "periodic_gc_runs %llu ",
ndts->ndts_periodic_gc_runs);
print_u64(PRINT_ANY, "forced_gc_runs", "forced_gc_runs %llu ",
ndts->ndts_forced_gc_runs);
print_nl();
}
static int print_ntable(struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE *)arg;
struct ndtmsg *ndtm = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr *tb[NDTA_MAX+1];
struct rtattr *tpb[NDTPA_MAX+1];
int ret;
if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
return 0;
}
len -= NLMSG_LENGTH(sizeof(*ndtm));
if (len < 0) {
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
return -1;
}
if (preferred_family && preferred_family != ndtm->ndtm_family)
return 0;
parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));
if (tb[NDTA_NAME]) {
const char *name = rta_getattr_str(tb[NDTA_NAME]);
if (filter.name && strcmp(filter.name, name))
return 0;
}
if (tb[NDTA_PARMS]) {
parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
RTA_PAYLOAD(tb[NDTA_PARMS]));
if (tpb[NDTPA_IFINDEX]) {
__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
if (filter.index && filter.index != ifindex)
return 0;
} else {
if (filter.index && filter.index != NONE_DEV)
return 0;
}
}
open_json_object(NULL);
print_string(PRINT_ANY, "family",
"%s ", family_name(ndtm->ndtm_family));
if (tb[NDTA_NAME]) {
const char *name = rta_getattr_str(tb[NDTA_NAME]);
print_string(PRINT_ANY, "name", "%s ", name);
}
print_nl();
ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
tb[NDTA_GC_INTERVAL]);
if (ret)
print_string(PRINT_FP, NULL, " ", NULL);
if (tb[NDTA_THRESH1]) {
__u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
print_uint(PRINT_ANY, "thresh1", "thresh1 %u ", thresh1);
}
if (tb[NDTA_THRESH2]) {
__u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
print_uint(PRINT_ANY, "thresh2", "thresh2 %u ", thresh2);
}
if (tb[NDTA_THRESH3]) {
__u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
print_uint(PRINT_ANY, "thresh3", "thresh3 %u ", thresh3);
}
if (tb[NDTA_GC_INTERVAL]) {
__u64 gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
print_u64(PRINT_ANY, "gc_interval", "gc_int %llu ", gc_int);
}
if (ret)
print_nl();
if (tb[NDTA_CONFIG] && show_stats)
print_ndtconfig(RTA_DATA(tb[NDTA_CONFIG]));
if (tb[NDTA_PARMS])
print_ndtparams(tpb);
if (tb[NDTA_STATS] && show_stats)
print_ndtstats(RTA_DATA(tb[NDTA_STATS]));
print_string(PRINT_FP, NULL, "\n", "");
close_json_object();
fflush(fp);
return 0;
}
static void ipntable_reset_filter(void)
{
memset(&filter, 0, sizeof(filter));
}
static int ipntable_show(int argc, char **argv)
{
ipntable_reset_filter();
filter.family = preferred_family;
while (argc > 0) {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
if (strcmp("none", *argv) == 0)
filter.index = NONE_DEV;
else if ((filter.index = ll_name_to_index(*argv)) == 0)
invarg("\"DEV\" is invalid", *argv);
} else if (strcmp(*argv, "name") == 0) {
NEXT_ARG();
filter.name = *argv;
} else
invarg("unknown", *argv);
argc--; argv++;
}
if (rtnl_neightbldump_req(&rth, preferred_family) < 0) {
perror("Cannot send dump request");
exit(1);
}
new_json_obj(json);
if (rtnl_dump_filter(&rth, print_ntable, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
delete_json_obj();
return 0;
}
int do_ipntable(int argc, char **argv)
{
ll_init_map(&rth);
if (argc > 0) {
if (matches(*argv, "change") == 0 ||
matches(*argv, "chg") == 0)
return ipntable_modify(RTM_SETNEIGHTBL,
NLM_F_REPLACE,
argc-1, argv+1);
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return ipntable_show(argc-1, argv+1);
if (matches(*argv, "help") == 0)
usage();
} else
return ipntable_show(0, NULL);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip ntable help\".\n", *argv);
exit(-1);
}