mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-18 23:50:12 +00:00

There is a couple of places where we report error in case of no network device is found. In all of them we output message in the same format to stderr and either return -1 or 1 to the caller or exit with -1. Introduce new helper function nodev() that takes name of the network device caused error and returns -1 to it's caller. Either call exit() or return to the caller to preserve behaviour before change. Use -nodev() in traffic control (tc) code to return 1. Simplify expression for checking for argument being 0/NULL in @if statement. Signed-off-by: Serhey Popovych <serhe.popovych@gmail.com>
698 lines
17 KiB
C
698 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_string(PRINT_FP, NULL, "%s", _SL_);
|
|
|
|
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_string(PRINT_FP, NULL, "%s", _SL_);
|
|
|
|
print_uint(PRINT_ANY, "hash_rnd",
|
|
" hash_rnd %u ", ndtc->ndtc_hash_rnd);
|
|
print_0xhex(PRINT_ANY, "hash_mask",
|
|
"hash_mask %08x ", 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_string(PRINT_FP, NULL, "%s", _SL_);
|
|
}
|
|
|
|
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_string(PRINT_FP, NULL, "%s", _SL_);
|
|
}
|
|
|
|
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_uint(PRINT_ANY, "reachable",
|
|
"reachable %llu ", reachable);
|
|
}
|
|
|
|
if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
|
|
__u64 breachable
|
|
= rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
|
|
|
|
print_uint(PRINT_ANY, "base_reachable",
|
|
"base_reachable %llu ", breachable);
|
|
}
|
|
|
|
if (tpb[NDTPA_RETRANS_TIME]) {
|
|
__u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
|
|
|
|
print_uint(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_uint(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_uint(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_uint(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_uint(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_uint(PRINT_ANY, "locktime", "locktime %llu ", locktime);
|
|
}
|
|
|
|
print_string(PRINT_FP, NULL, "%s", _SL_);
|
|
}
|
|
|
|
static void print_ndtstats(const struct ndt_stats *ndts)
|
|
{
|
|
|
|
print_string(PRINT_FP, NULL, " stats ", NULL);
|
|
|
|
print_uint(PRINT_ANY, "allocs", "allocs %llu ", ndts->ndts_allocs);
|
|
print_uint(PRINT_ANY, "destroys", "destroys %llu ",
|
|
ndts->ndts_destroys);
|
|
print_uint(PRINT_ANY, "hash_grows", "hash_grows %llu ",
|
|
ndts->ndts_hash_grows);
|
|
|
|
print_string(PRINT_FP, NULL, "%s ", _SL_);
|
|
|
|
print_uint(PRINT_ANY, "res_failed", "res_failed %llu ",
|
|
ndts->ndts_res_failed);
|
|
print_uint(PRINT_ANY, "lookups", "lookups %llu ", ndts->ndts_lookups);
|
|
print_uint(PRINT_ANY, "hits", "hits %llu ", ndts->ndts_hits);
|
|
|
|
print_string(PRINT_FP, NULL, "%s ", _SL_);
|
|
|
|
print_uint(PRINT_ANY, "rcv_probes_mcast", "rcv_probes_mcast %llu ",
|
|
ndts->ndts_rcv_probes_mcast);
|
|
print_uint(PRINT_ANY, "rcv_probes_ucast", "rcv_probes_ucast %llu ",
|
|
ndts->ndts_rcv_probes_ucast);
|
|
|
|
print_string(PRINT_FP, NULL, "%s ", _SL_);
|
|
|
|
print_uint(PRINT_ANY, "periodic_gc_runs", "periodic_gc_runs %llu ",
|
|
ndts->ndts_periodic_gc_runs);
|
|
print_uint(PRINT_ANY, "forced_gc_runs", "forced_gc_runs %llu ",
|
|
ndts->ndts_forced_gc_runs);
|
|
|
|
print_string(PRINT_FP, NULL, "%s", _SL_);
|
|
}
|
|
|
|
static int print_ntable(const struct sockaddr_nl *who,
|
|
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_string(PRINT_FP, NULL, "%s", _SL_);
|
|
|
|
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_uint(PRINT_ANY, "gc_interval", "gc_int %llu ", gc_int);
|
|
}
|
|
|
|
if (ret)
|
|
print_string(PRINT_FP, NULL, "%s", _SL_);
|
|
|
|
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_wilddump_request(&rth, preferred_family, RTM_GETNEIGHTBL) < 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);
|
|
}
|