Merge branch 'net-next'

This commit is contained in:
Stephen Hemminger 2017-09-05 09:48:36 -07:00
commit 01e5409371
82 changed files with 4059 additions and 1507 deletions

1
.gitignore vendored
View File

@ -1,6 +1,5 @@
static-syms.h
config.*
Config
*.o
*.a
*.so

View File

@ -54,12 +54,12 @@ SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma man
LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
LDLIBS += $(LIBNETLINK)
all: Config
all: config.mk
@set -e; \
for i in $(SUBDIRS); \
do echo; echo $$i; $(MAKE) $(MFLAGS) -C $$i; done
Config:
config.mk:
sh configure $(KERNEL_INCLUDE)
install: all
@ -88,9 +88,9 @@ clean:
do $(MAKE) $(MFLAGS) -C $$i clean; done
clobber:
touch Config
touch config.mk
$(MAKE) $(MFLAGS) clean
rm -f Config cscope.*
rm -f config.mk cscope.*
distclean: clobber

5
README
View File

@ -21,8 +21,9 @@ database routines. Often this is in the db-devel package.
2. make
The makefile will automatically build a Config file which
contains whether or not ATM is available, etc.
The makefile will automatically build a config.mk file which
contains definitions of libraries that may or may not be available
on the system such as: ATM, ELF, MNL, and SELINUX.
3. To make documentation, cd to doc/ directory , then
look at start of Makefile and set correct values for

View File

@ -1,15 +1,6 @@
BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o
include ../Config
ifeq ($(IP_CONFIG_SETNS),y)
CFLAGS += -DHAVE_SETNS
endif
ifeq ($(HAVE_MNL),y)
CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags)
LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)
endif
include ../config.mk
all: bridge

View File

@ -13,6 +13,7 @@
#include <linux/if_ether.h>
#include <string.h>
#include <arpa/inet.h>
#include <json_writer.h>
#include "libnetlink.h"
#include "br_common.h"
@ -25,6 +26,9 @@
#endif
static unsigned int filter_index, filter_vlan;
json_writer_t *jw_global;
static bool print_mdb_entries = true;
static bool print_mdb_router = true;
static void usage(void)
{
@ -49,13 +53,26 @@ static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
if (tb[MDBA_ROUTER_PATTR_TIMER]) {
__jiffies_to_tv(&tv,
rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
fprintf(f, " %4i.%.2i",
(int)tv.tv_sec, (int)tv.tv_usec/10000);
if (jw_global) {
char formatted_time[9];
snprintf(formatted_time, sizeof(formatted_time),
"%4i.%.2i", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
jsonw_string_field(jw_global, "timer", formatted_time);
} else {
fprintf(f, " %4i.%.2i",
(int)tv.tv_sec, (int)tv.tv_usec/10000);
}
}
if (tb[MDBA_ROUTER_PATTR_TYPE]) {
type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
fprintf(f, " %s",
is_temp_mcast_rtr(type) ? "temp" : "permanent");
if (jw_global)
jsonw_string_field(jw_global, "type",
is_temp_mcast_rtr(type) ? "temp" : "permanent");
else
fprintf(f, " %s",
is_temp_mcast_rtr(type) ? "temp" : "permanent");
}
}
@ -65,24 +82,50 @@ static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx)
struct rtattr *i;
int rem;
if (!show_stats)
fprintf(f, "router ports on %s: ", ll_index_to_name(brifidx));
rem = RTA_PAYLOAD(attr);
for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
port_ifindex = RTA_DATA(i);
if (show_stats) {
fprintf(f, "router ports on %s: %s",
ll_index_to_name(brifidx),
ll_index_to_name(*port_ifindex));
__print_router_port_stats(f, i);
fprintf(f, "\n");
} else {
fprintf(f, "%s ", ll_index_to_name(*port_ifindex));
if (jw_global) {
jsonw_name(jw_global, ll_index_to_name(brifidx));
jsonw_start_array(jw_global);
for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
port_ifindex = RTA_DATA(i);
jsonw_start_object(jw_global);
jsonw_string_field(jw_global,
"port",
ll_index_to_name(*port_ifindex));
if (show_stats)
__print_router_port_stats(f, i);
jsonw_end_object(jw_global);
}
jsonw_end_array(jw_global);
} else {
if (!show_stats)
fprintf(f, "router ports on %s: ",
ll_index_to_name(brifidx));
for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
port_ifindex = RTA_DATA(i);
if (show_stats) {
fprintf(f, "router ports on %s: %s",
ll_index_to_name(brifidx),
ll_index_to_name(*port_ifindex));
__print_router_port_stats(f, i);
fprintf(f, "\n");
} else{
fprintf(f, "%s ",
ll_index_to_name(*port_ifindex));
}
}
if (!show_stats)
fprintf(f, "\n");
}
if (!show_stats)
fprintf(f, "\n");
}
static void start_json_mdb_flags_array(bool *mdb_flags)
{
if (*mdb_flags)
return;
jsonw_name(jw_global, "flags");
jsonw_start_array(jw_global);
*mdb_flags = true;
}
static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
@ -91,28 +134,70 @@ static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
SPRINT_BUF(abuf);
const void *src;
int af;
bool mdb_flags = false;
if (filter_vlan && e->vid != filter_vlan)
return;
af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
(const void *)&e->addr.u.ip6;
if (n->nlmsg_type == RTM_DELMDB)
fprintf(f, "Deleted ");
fprintf(f, "dev %s port %s grp %s %s %s", ll_index_to_name(ifindex),
ll_index_to_name(e->ifindex),
inet_ntop(af, src, abuf, sizeof(abuf)),
(e->state & MDB_PERMANENT) ? "permanent" : "temp",
(e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
if (e->vid)
fprintf(f, " vid %hu", e->vid);
if (jw_global)
jsonw_start_object(jw_global);
if (n->nlmsg_type == RTM_DELMDB) {
if (jw_global)
jsonw_string_field(jw_global, "opCode", "deleted");
else
fprintf(f, "Deleted ");
}
if (jw_global) {
jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex));
jsonw_string_field(jw_global,
"port",
ll_index_to_name(e->ifindex));
jsonw_string_field(jw_global, "grp", inet_ntop(af, src,
abuf, sizeof(abuf)));
jsonw_string_field(jw_global, "state",
(e->state & MDB_PERMANENT) ? "permanent" : "temp");
if (e->flags & MDB_FLAGS_OFFLOAD) {
start_json_mdb_flags_array(&mdb_flags);
jsonw_string(jw_global, "offload");
}
if (mdb_flags)
jsonw_end_array(jw_global);
} else{
fprintf(f, "dev %s port %s grp %s %s %s",
ll_index_to_name(ifindex),
ll_index_to_name(e->ifindex),
inet_ntop(af, src, abuf, sizeof(abuf)),
(e->state & MDB_PERMANENT) ? "permanent" : "temp",
(e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
}
if (e->vid) {
if (jw_global)
jsonw_uint_field(jw_global, "vid", e->vid);
else
fprintf(f, " vid %hu", e->vid);
}
if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
struct timeval tv;
__jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
fprintf(f, "%4i.%.2i", (int)tv.tv_sec, (int)tv.tv_usec/10000);
if (jw_global) {
char formatted_time[9];
snprintf(formatted_time, sizeof(formatted_time),
"%4i.%.2i", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
jsonw_string_field(jw_global, "timer", formatted_time);
} else {
fprintf(f, "%4i.%.2i", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
}
}
fprintf(f, "\n");
if (jw_global)
jsonw_end_object(jw_global);
else
fprintf(f, "\n");
}
static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
@ -157,14 +242,14 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
if (tb[MDBA_MDB]) {
if (tb[MDBA_MDB] && print_mdb_entries) {
int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
br_print_mdb_entry(fp, r->ifindex, i, n);
}
if (tb[MDBA_ROUTER]) {
if (tb[MDBA_ROUTER] && print_mdb_router) {
if (n->nlmsg_type == RTM_GETMDB) {
if (show_details)
br_print_router_ports(fp, tb[MDBA_ROUTER],
@ -174,15 +259,33 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
i = RTA_DATA(tb[MDBA_ROUTER]);
port_ifindex = RTA_DATA(i);
if (n->nlmsg_type == RTM_DELMDB)
fprintf(fp, "Deleted ");
fprintf(fp, "router port dev %s master %s\n",
ll_index_to_name(*port_ifindex),
ll_index_to_name(r->ifindex));
if (n->nlmsg_type == RTM_DELMDB) {
if (jw_global)
jsonw_string_field(jw_global,
"opCode",
"deleted");
else
fprintf(fp, "Deleted ");
}
if (jw_global) {
jsonw_name(jw_global,
ll_index_to_name(r->ifindex));
jsonw_start_array(jw_global);
jsonw_start_object(jw_global);
jsonw_string_field(jw_global, "port",
ll_index_to_name(*port_ifindex));
jsonw_end_object(jw_global);
jsonw_end_array(jw_global);
} else {
fprintf(fp, "router port dev %s master %s\n",
ll_index_to_name(*port_ifindex),
ll_index_to_name(r->ifindex));
}
}
}
fflush(fp);
if (!jw_global)
fflush(fp);
return 0;
}
@ -215,15 +318,54 @@ static int mdb_show(int argc, char **argv)
}
}
/* get mdb entries*/
if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
perror("Cannot send dump request");
return -1;
}
if (!json_output) {
/* Normal output */
if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return -1;
}
return 0;
}
/* Json output */
jw_global = jsonw_new(stdout);
jsonw_pretty(jw_global, 1);
jsonw_start_object(jw_global);
jsonw_name(jw_global, "mdb");
jsonw_start_array(jw_global);
/* print mdb entries */
print_mdb_entries = true;
print_mdb_router = false;
if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return -1;
}
jsonw_end_array(jw_global);
/* get router ports */
if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
perror("Cannot send dump request");
return -1;
}
jsonw_name(jw_global, "router");
jsonw_start_object(jw_global);
/* print router ports */
print_mdb_entries = false;
print_mdb_router = true;
if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return -1;
}
jsonw_end_object(jw_global);
jsonw_end_object(jw_global);
jsonw_destroy(&jw_global);
return 0;
}

81
configure vendored
View File

@ -3,6 +3,9 @@
#
INCLUDE=${1:-"$PWD/include"}
# Output file which is input to Makefile
CONFIG=config.mk
# Make a temp directory in build tree.
TMPDIR=$(mktemp -d config.XXXXXX)
trap 'status=$?; rm -rf $TMPDIR; exit $status' EXIT HUP INT QUIT TERM
@ -10,7 +13,7 @@ trap 'status=$?; rm -rf $TMPDIR; exit $status' EXIT HUP INT QUIT TERM
check_prog()
{
echo -n "$2"
command -v $1 >/dev/null 2>&1 && (echo "$3:=y" >> Config; echo "yes") || (echo "no"; return 1)
command -v $1 >/dev/null 2>&1 && (echo "$3:=y" >> $CONFIG; echo "yes") || (echo "no"; return 1)
}
check_docs()
@ -30,9 +33,9 @@ check_toolchain()
: ${PKG_CONFIG:=pkg-config}
: ${AR=ar}
: ${CC=gcc}
echo "PKG_CONFIG:=${PKG_CONFIG}" >>Config
echo "AR:=${AR}" >>Config
echo "CC:=${CC}" >>Config
echo "PKG_CONFIG:=${PKG_CONFIG}" >>$CONFIG
echo "AR:=${AR}" >>$CONFIG
echo "CC:=${CC}" >>$CONFIG
}
check_atm()
@ -49,7 +52,7 @@ EOF
$CC -I$INCLUDE -o $TMPDIR/atmtest $TMPDIR/atmtest.c -latm >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "TC_CONFIG_ATM:=y" >>Config
echo "TC_CONFIG_ATM:=y" >>$CONFIG
echo yes
else
echo no
@ -61,7 +64,7 @@ check_xtables()
{
if ! ${PKG_CONFIG} xtables --exists
then
echo "TC_CONFIG_NO_XT:=y" >>Config
echo "TC_CONFIG_NO_XT:=y" >>$CONFIG
fi
}
@ -90,7 +93,7 @@ EOF
if $CC -I$INCLUDE $IPTC -o $TMPDIR/ipttest $TMPDIR/ipttest.c $IPTL \
$(${PKG_CONFIG} xtables --cflags --libs) -ldl >/dev/null 2>&1
then
echo "TC_CONFIG_XT:=y" >>Config
echo "TC_CONFIG_XT:=y" >>$CONFIG
echo "using xtables"
fi
rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest
@ -99,7 +102,7 @@ EOF
check_xt_old()
{
# bail if previous XT checks has already succeded.
if grep -q TC_CONFIG_XT Config
if grep -q TC_CONFIG_XT $CONFIG
then
return
fi
@ -129,7 +132,7 @@ EOF
$CC -I$INCLUDE $IPTC -o $TMPDIR/ipttest $TMPDIR/ipttest.c $IPTL -ldl >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "TC_CONFIG_XT_OLD:=y" >>Config
echo "TC_CONFIG_XT_OLD:=y" >>$CONFIG
echo "using old xtables (no need for xt-internal.h)"
fi
rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest
@ -138,7 +141,7 @@ EOF
check_xt_old_internal_h()
{
# bail if previous XT checks has already succeded.
if grep -q TC_CONFIG_XT Config
if grep -q TC_CONFIG_XT $CONFIG
then
return
fi
@ -170,14 +173,14 @@ EOF
if [ $? -eq 0 ]
then
echo "using old xtables with xt-internal.h"
echo "TC_CONFIG_XT_OLD_H:=y" >>Config
echo "TC_CONFIG_XT_OLD_H:=y" >>$CONFIG
fi
rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest
}
check_ipt()
{
if ! grep TC_CONFIG_XT Config > /dev/null
if ! grep TC_CONFIG_XT $CONFIG > /dev/null
then
echo "using iptables"
fi
@ -188,7 +191,7 @@ check_ipt_lib_dir()
IPT_LIB_DIR=$(${PKG_CONFIG} --variable=xtlibdir xtables)
if [ -n "$IPT_LIB_DIR" ]; then
echo $IPT_LIB_DIR
echo "IPT_LIB_DIR:=$IPT_LIB_DIR" >> Config
echo "IPT_LIB_DIR:=$IPT_LIB_DIR" >> $CONFIG
return
fi
@ -197,7 +200,7 @@ check_ipt_lib_dir()
for file in $dir/{xtables,iptables}/lib*t_*so ; do
if [ -f $file ]; then
echo ${file%/*}
echo "IPT_LIB_DIR:=${file%/*}" >> Config
echo "IPT_LIB_DIR:=${file%/*}" >> $CONFIG
return
fi
done
@ -218,8 +221,9 @@ EOF
$CC -I$INCLUDE -o $TMPDIR/setnstest $TMPDIR/setnstest.c >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "IP_CONFIG_SETNS:=y" >>Config
echo "IP_CONFIG_SETNS:=y" >>$CONFIG
echo "yes"
echo "CFLAGS += -DHAVE_SETNS" >>$CONFIG
else
echo "no"
fi
@ -249,7 +253,7 @@ EOF
if $CC -I$INCLUDE -o $TMPDIR/ipsettest $TMPDIR/ipsettest.c >/dev/null 2>&1
then
echo "TC_CONFIG_IPSET:=y" >>Config
echo "TC_CONFIG_IPSET:=y" >>$CONFIG
echo "yes"
else
echo "no"
@ -259,25 +263,16 @@ EOF
check_elf()
{
cat >$TMPDIR/elftest.c <<EOF
#include <libelf.h>
#include <gelf.h>
int main(void)
{
Elf_Scn *scn __attribute__((__unused__));
GElf_Shdr shdr __attribute__((__unused__));;
return elf_version(EV_CURRENT);
}
EOF
if $CC -I$INCLUDE -o $TMPDIR/elftest $TMPDIR/elftest.c -lelf >/dev/null 2>&1
if ${PKG_CONFIG} libelf --exists
then
echo "HAVE_ELF:=y" >>Config
echo "HAVE_ELF:=y" >>$CONFIG
echo "yes"
echo 'CFLAGS += -DHAVE_ELF' `${PKG_CONFIG} libelf --cflags` >> $CONFIG
echo 'LDLIBS += ' `${PKG_CONFIG} libelf --libs` >>$CONFIG
else
echo "no"
fi
rm -f $TMPDIR/elftest.c $TMPDIR/elftest
}
check_selinux()
@ -285,8 +280,11 @@ check_selinux()
{
if ${PKG_CONFIG} libselinux --exists
then
echo "HAVE_SELINUX:=y" >>Config
echo "HAVE_SELINUX:=y" >>$CONFIG
echo "yes"
echo 'LDLIBS +=' `${PKG_CONFIG} --libs libselinux` >>$CONFIG
echo 'CFLAGS += -DHAVE_SELINUX' `${PKG_CONFIG} --cflags libselinux` >>$CONFIG
else
echo "no"
fi
@ -296,8 +294,11 @@ check_mnl()
{
if ${PKG_CONFIG} libmnl --exists
then
echo "HAVE_MNL:=y" >>Config
echo "HAVE_MNL:=y" >>$CONFIG
echo "yes"
echo 'CFLAGS += -DHAVE_LIBMNL' `${PKG_CONFIG} libmnl --cflags` >>$CONFIG
echo 'LDLIBS +=' `${PKG_CONFIG} libmnl --libs` >> $CONFIG
else
echo "no"
fi
@ -317,7 +318,7 @@ EOF
$CC -I$INCLUDE -o $TMPDIR/dbtest $TMPDIR/dbtest.c -ldb >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "HAVE_BERKELEY_DB:=y" >>Config
echo "HAVE_BERKELEY_DB:=y" >>$CONFIG
echo "yes"
else
echo "no"
@ -351,8 +352,8 @@ endif
EOF
}
echo "# Generated config based on" $INCLUDE >Config
quiet_config >> Config
echo "# Generated config based on" $INCLUDE >$CONFIG
quiet_config >> $CONFIG
check_toolchain
@ -362,7 +363,7 @@ echo -n " ATM "
check_atm
check_xtables
if ! grep -q TC_CONFIG_NO_XT Config
if ! grep -q TC_CONFIG_NO_XT $CONFIG
then
echo -n " IPT "
check_xt
@ -375,7 +376,7 @@ then
fi
echo
if ! grep -q TC_CONFIG_NO_XT Config
if ! grep -q TC_CONFIG_NO_XT $CONFIG
then
echo -n "iptables modules directory: "
check_ipt_lib_dir
@ -401,6 +402,6 @@ echo -n "docs:"
check_docs
echo
echo >> Config
echo "%.o: %.c" >> Config
echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<' >> Config
echo >> $CONFIG
echo "%.o: %.c" >> $CONFIG
echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<' >> $CONFIG

View File

@ -1,4 +1,5 @@
include ../Config
include ../config.mk
ifeq ($(HAVE_MNL),y)
DEVLINKOBJ = devlink.o mnlg.o

View File

@ -1,6 +1,6 @@
GENLOBJ=genl.o
include ../Config
include ../config.mk
SHARED_LIBS ?= y
CFLAGS += -fno-strict-aliasing
@ -17,11 +17,6 @@ LDFLAGS += -Wl,-export-dynamic
LDLIBS += -lm -ldl
endif
ifeq ($(HAVE_MNL),y)
CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags)
LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)
endif
all: genl
genl: $(GENLOBJ) $(LIBNETLINK) $(LIBUTIL) $(GENLLIB)

View File

@ -2,6 +2,7 @@
#define __COLOR_H__ 1
enum color_attr {
COLOR_NONE,
COLOR_IFNAME,
COLOR_MAC,
COLOR_INET,
@ -12,6 +13,7 @@ enum color_attr {
};
void enable_color(void);
void check_if_color_enabled(void);
void set_color_palette(void);
int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...);
enum color_attr ifa_family_color(__u8 ifa_family);

View File

@ -33,20 +33,29 @@ void jsonw_pretty(json_writer_t *self, bool on);
void jsonw_name(json_writer_t *self, const char *name);
/* Add value */
void jsonw_printf(json_writer_t *self, const char *fmt, ...);
void jsonw_string(json_writer_t *self, const char *value);
void jsonw_bool(json_writer_t *self, bool value);
void jsonw_float(json_writer_t *self, double number);
void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num);
void jsonw_uint(json_writer_t *self, uint64_t number);
void jsonw_hu(json_writer_t *self, unsigned short number);
void jsonw_int(json_writer_t *self, int64_t number);
void jsonw_null(json_writer_t *self);
void jsonw_lluint(json_writer_t *self, unsigned long long int num);
/* Useful Combinations of name and value */
void jsonw_string_field(json_writer_t *self, const char *prop, const char *val);
void jsonw_bool_field(json_writer_t *self, const char *prop, bool value);
void jsonw_float_field(json_writer_t *self, const char *prop, double num);
void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num);
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num);
void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num);
void jsonw_null_field(json_writer_t *self, const char *prop);
void jsonw_lluint_field(json_writer_t *self, const char *prop,
unsigned long long int num);
void jsonw_float_field_fmt(json_writer_t *self, const char *prop,
const char *fmt, double val);
/* Collections */
void jsonw_start_object(json_writer_t *self);

View File

@ -30,9 +30,14 @@
#define BPF_FROM_LE BPF_TO_LE
#define BPF_FROM_BE BPF_TO_BE
/* jmp encodings */
#define BPF_JNE 0x50 /* jump != */
#define BPF_JLT 0xa0 /* LT is unsigned, '<' */
#define BPF_JLE 0xb0 /* LE is unsigned, '<=' */
#define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */
#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */
#define BPF_JSLT 0xc0 /* SLT is signed, '<' */
#define BPF_JSLE 0xd0 /* SLE is signed, '<=' */
#define BPF_CALL 0x80 /* function call */
#define BPF_EXIT 0x90 /* function return */
@ -104,6 +109,8 @@ enum bpf_map_type {
BPF_MAP_TYPE_LPM_TRIE,
BPF_MAP_TYPE_ARRAY_OF_MAPS,
BPF_MAP_TYPE_HASH_OF_MAPS,
BPF_MAP_TYPE_DEVMAP,
BPF_MAP_TYPE_SOCKMAP,
};
enum bpf_prog_type {
@ -121,6 +128,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_LWT_OUT,
BPF_PROG_TYPE_LWT_XMIT,
BPF_PROG_TYPE_SOCK_OPS,
BPF_PROG_TYPE_SK_SKB,
};
enum bpf_attach_type {
@ -128,6 +136,8 @@ enum bpf_attach_type {
BPF_CGROUP_INET_EGRESS,
BPF_CGROUP_INET_SOCK_CREATE,
BPF_CGROUP_SOCK_OPS,
BPF_SK_SKB_STREAM_PARSER,
BPF_SK_SKB_STREAM_VERDICT,
__MAX_BPF_ATTACH_TYPE
};
@ -153,6 +163,7 @@ enum bpf_attach_type {
#define BPF_NOEXIST 1 /* create new element if it didn't exist */
#define BPF_EXIST 2 /* update existing element */
/* flags for BPF_MAP_CREATE command */
#define BPF_F_NO_PREALLOC (1U << 0)
/* Instead of having one common LRU list in the
* BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list
@ -161,6 +172,8 @@ enum bpf_attach_type {
* across different LRU lists.
*/
#define BPF_F_NO_COMMON_LRU (1U << 1)
/* Specify numa node during map creation */
#define BPF_F_NUMA_NODE (1U << 2)
union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
@ -168,8 +181,13 @@ union bpf_attr {
__u32 key_size; /* size of key in bytes */
__u32 value_size; /* size of value in bytes */
__u32 max_entries; /* max number of entries in a map */
__u32 map_flags; /* prealloc or not */
__u32 map_flags; /* BPF_MAP_CREATE related
* flags defined above.
*/
__u32 inner_map_fd; /* fd pointing to the inner map */
__u32 numa_node; /* numa node (effective only if
* BPF_F_NUMA_NODE is set).
*/
};
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
@ -344,9 +362,20 @@ union bpf_attr {
* int bpf_redirect(ifindex, flags)
* redirect to another netdev
* @ifindex: ifindex of the net device
* @flags: bit 0 - if set, redirect to ingress instead of egress
* other bits - reserved
* Return: TC_ACT_REDIRECT
* @flags:
* cls_bpf:
* bit 0 - if set, redirect to ingress instead of egress
* other bits - reserved
* xdp_bpf:
* all bits - reserved
* Return: cls_bpf: TC_ACT_REDIRECT on success or TC_ACT_SHOT on error
* xdp_bfp: XDP_REDIRECT on success or XDP_ABORT on error
* int bpf_redirect_map(map, key, flags)
* redirect to endpoint in map
* @map: pointer to dev map
* @key: index in map to lookup
* @flags: --
* Return: XDP_REDIRECT on success or XDP_ABORT on error
*
* u32 bpf_get_route_realm(skb)
* retrieve a dst's tclassid
@ -539,6 +568,20 @@ union bpf_attr {
* @mode: operation mode (enum bpf_adj_room_mode)
* @flags: reserved for future use
* Return: 0 on success or negative error code
*
* int bpf_sk_redirect_map(map, key, flags)
* Redirect skb to a sock in map using key as a lookup key for the
* sock in map.
* @map: pointer to sockmap
* @key: key to lookup sock in map
* @flags: reserved for future use
* Return: SK_REDIRECT
*
* int bpf_sock_map_update(skops, map, key, flags)
* @skops: pointer to bpf_sock_ops
* @map: pointer to sockmap to update
* @key: key to insert/update sock in map
* @flags: same flags as map update elem
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@ -591,7 +634,10 @@ union bpf_attr {
FN(get_socket_uid), \
FN(set_hash), \
FN(setsockopt), \
FN(skb_adjust_room),
FN(skb_adjust_room), \
FN(redirect_map), \
FN(sk_redirect_map), \
FN(sock_map_update), \
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
@ -668,6 +714,15 @@ struct __sk_buff {
__u32 data;
__u32 data_end;
__u32 napi_id;
/* accessed by BPF_PROG_TYPE_sk_skb types */
__u32 family;
__u32 remote_ip4; /* Stored in network byte order */
__u32 local_ip4; /* Stored in network byte order */
__u32 remote_ip6[4]; /* Stored in network byte order */
__u32 local_ip6[4]; /* Stored in network byte order */
__u32 remote_port; /* Stored in network byte order */
__u32 local_port; /* stored in host byte order */
};
struct bpf_tunnel_key {
@ -703,6 +758,8 @@ struct bpf_sock {
__u32 family;
__u32 type;
__u32 protocol;
__u32 mark;
__u32 priority;
};
#define XDP_PACKET_HEADROOM 256
@ -717,6 +774,7 @@ enum xdp_action {
XDP_DROP,
XDP_PASS,
XDP_TX,
XDP_REDIRECT,
};
/* user accessible metadata for XDP packet hook
@ -727,6 +785,12 @@ struct xdp_md {
__u32 data_end;
};
enum sk_action {
SK_ABORTED = 0,
SK_DROP,
SK_REDIRECT,
};
#define BPF_TAG_SIZE 8
struct bpf_prog_info {

View File

@ -226,4 +226,22 @@ enum devlink_dpipe_action_type {
DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY,
};
enum devlink_dpipe_field_ethernet_id {
DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
};
enum devlink_dpipe_field_ipv4_id {
DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
};
enum devlink_dpipe_field_ipv6_id {
DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
};
enum devlink_dpipe_header_id {
DEVLINK_DPIPE_HEADER_ETHERNET,
DEVLINK_DPIPE_HEADER_IPV4,
DEVLINK_DPIPE_HEADER_IPV6,
};
#endif /* _LINUX_DEVLINK_H_ */

View File

@ -59,6 +59,7 @@
#define ARPHRD_LAPB 516 /* LAPB */
#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */
#define ARPHRD_RAWHDLC 518 /* Raw HDLC */
#define ARPHRD_RAWIP 519 /* Raw IP */
#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */

View File

@ -66,6 +66,7 @@
#define ETH_P_ATALK 0x809B /* Appletalk DDP */
#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
#define ETH_P_ERSPAN 0x88BE /* ERSPAN type II */
#define ETH_P_IPX 0x8137 /* IPX over DIX */
#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
#define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */
@ -98,11 +99,13 @@
#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
#define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */
#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */
#define ETH_P_NSH 0x894F /* Network Service Header */
#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */
#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */
#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value
@ -137,6 +140,9 @@
#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */
#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */
#define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */
#define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and
* aggregation protocol
*/
/*
* This is an Ethernet frame header.

View File

@ -134,6 +134,7 @@ enum {
IFLA_GRE_COLLECT_METADATA,
IFLA_GRE_IGNORE_DF,
IFLA_GRE_FWMARK,
IFLA_GRE_ERSPAN_INDEX,
__IFLA_GRE_MAX,
};

View File

@ -142,6 +142,8 @@ enum {
INET_DIAG_PAD,
INET_DIAG_MARK,
INET_DIAG_BBRINFO,
INET_DIAG_CLASS_ID,
INET_DIAG_MD5SIG,
__INET_DIAG_MAX,
};

View File

@ -1,192 +0,0 @@
#ifndef _IPV6_H
#define _IPV6_H
#include <linux/libc-compat.h>
#include <linux/types.h>
#include <linux/in6.h>
#include <asm/byteorder.h>
/* The latest drafts declared increase in minimal mtu up to 1280. */
#define IPV6_MIN_MTU 1280
/*
* Advanced API
* source interface/address selection, source routing, etc...
* *under construction*
*/
#if __UAPI_DEF_IN6_PKTINFO
struct in6_pktinfo {
struct in6_addr ipi6_addr;
int ipi6_ifindex;
};
#endif
#if __UAPI_DEF_IP6_MTUINFO
struct ip6_mtuinfo {
struct sockaddr_in6 ip6m_addr;
__u32 ip6m_mtu;
};
#endif
struct in6_ifreq {
struct in6_addr ifr6_addr;
__u32 ifr6_prefixlen;
int ifr6_ifindex;
};
#define IPV6_SRCRT_STRICT 0x01 /* Deprecated; will be removed */
#define IPV6_SRCRT_TYPE_0 0 /* Deprecated; will be removed */
#define IPV6_SRCRT_TYPE_2 2 /* IPv6 type 2 Routing Header */
#define IPV6_SRCRT_TYPE_4 4 /* Segment Routing with IPv6 */
/*
* routing header
*/
struct ipv6_rt_hdr {
__u8 nexthdr;
__u8 hdrlen;
__u8 type;
__u8 segments_left;
/*
* type specific data
* variable length field
*/
};
struct ipv6_opt_hdr {
__u8 nexthdr;
__u8 hdrlen;
/*
* TLV encoded option data follows.
*/
} __attribute__((packed)); /* required for some archs */
#define ipv6_destopt_hdr ipv6_opt_hdr
#define ipv6_hopopt_hdr ipv6_opt_hdr
/* Router Alert option values (RFC2711) */
#define IPV6_OPT_ROUTERALERT_MLD 0x0000 /* MLD(RFC2710) */
/*
* routing header type 0 (used in cmsghdr struct)
*/
struct rt0_hdr {
struct ipv6_rt_hdr rt_hdr;
__u32 reserved;
struct in6_addr addr[0];
#define rt0_type rt_hdr.type
};
/*
* routing header type 2
*/
struct rt2_hdr {
struct ipv6_rt_hdr rt_hdr;
__u32 reserved;
struct in6_addr addr;
#define rt2_type rt_hdr.type
};
/*
* home address option in destination options header
*/
struct ipv6_destopt_hao {
__u8 type;
__u8 length;
struct in6_addr addr;
} __attribute__((packed));
/*
* IPv6 fixed header
*
* BEWARE, it is incorrect. The first 4 bits of flow_lbl
* are glued to priority now, forming "class".
*/
struct ipv6hdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 priority:4,
version:4;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u8 version:4,
priority:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 flow_lbl[3];
__be16 payload_len;
__u8 nexthdr;
__u8 hop_limit;
struct in6_addr saddr;
struct in6_addr daddr;
};
/* index values for the variables in ipv6_devconf */
enum {
DEVCONF_FORWARDING = 0,
DEVCONF_HOPLIMIT,
DEVCONF_MTU6,
DEVCONF_ACCEPT_RA,
DEVCONF_ACCEPT_REDIRECTS,
DEVCONF_AUTOCONF,
DEVCONF_DAD_TRANSMITS,
DEVCONF_RTR_SOLICITS,
DEVCONF_RTR_SOLICIT_INTERVAL,
DEVCONF_RTR_SOLICIT_DELAY,
DEVCONF_USE_TEMPADDR,
DEVCONF_TEMP_VALID_LFT,
DEVCONF_TEMP_PREFERED_LFT,
DEVCONF_REGEN_MAX_RETRY,
DEVCONF_MAX_DESYNC_FACTOR,
DEVCONF_MAX_ADDRESSES,
DEVCONF_FORCE_MLD_VERSION,
DEVCONF_ACCEPT_RA_DEFRTR,
DEVCONF_ACCEPT_RA_PINFO,
DEVCONF_ACCEPT_RA_RTR_PREF,
DEVCONF_RTR_PROBE_INTERVAL,
DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
DEVCONF_PROXY_NDP,
DEVCONF_OPTIMISTIC_DAD,
DEVCONF_ACCEPT_SOURCE_ROUTE,
DEVCONF_MC_FORWARDING,
DEVCONF_DISABLE_IPV6,
DEVCONF_ACCEPT_DAD,
DEVCONF_FORCE_TLLAO,
DEVCONF_NDISC_NOTIFY,
DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL,
DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
DEVCONF_SUPPRESS_FRAG_NDISC,
DEVCONF_ACCEPT_RA_FROM_LOCAL,
DEVCONF_USE_OPTIMISTIC,
DEVCONF_ACCEPT_RA_MTU,
DEVCONF_STABLE_SECRET,
DEVCONF_USE_OIF_ADDRS_ONLY,
DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT,
DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
DEVCONF_DROP_UNSOLICITED_NA,
DEVCONF_KEEP_ADDR_ON_DOWN,
DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
DEVCONF_SEG6_ENABLED,
DEVCONF_SEG6_REQUIRE_HMAC,
DEVCONF_ENHANCED_DAD,
DEVCONF_ADDR_GEN_MODE,
DEVCONF_DISABLE_POLICY,
DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
DEVCONF_MAX
};
#endif /* _IPV6_H */

View File

@ -11,6 +11,7 @@ enum lwtunnel_encap_types {
LWTUNNEL_ENCAP_IP6,
LWTUNNEL_ENCAP_SEG6,
LWTUNNEL_ENCAP_BPF,
LWTUNNEL_ENCAP_SEG6_LOCAL,
__LWTUNNEL_ENCAP_MAX,
};

View File

@ -69,6 +69,9 @@ struct nlmsghdr {
#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
#define NLM_F_APPEND 0x800 /* Add to end of list */
/* Modifiers to DELETE request */
#define NLM_F_NONREC 0x100 /* Do not delete recursively */
/* Flags for ACK message */
#define NLM_F_CAPPED 0x100 /* request was capped */
#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
@ -222,5 +225,22 @@ struct nlattr {
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
/* Generic 32 bitflags attribute content sent to the kernel.
*
* The value is a bitmap that defines the values being set
* The selector is a bitmask that defines which value is legit
*
* Examples:
* value = 0x0, and selector = 0x1
* implies we are selecting bit 1 and we want to set its value to 0.
*
* value = 0x2, and selector = 0x2
* implies we are selecting bit 2 and we want to set its value to 1.
*
*/
struct nla_bitfield32 {
__u32 value;
__u32 selector;
};
#endif /* __LINUX_NETLINK_H */

383
include/linux/pfkeyv2.h Normal file
View File

@ -0,0 +1,383 @@
/* PF_KEY user interface, this is defined by rfc2367 so
* do not make arbitrary modifications or else this header
* file will not be compliant.
*/
#ifndef _LINUX_PFKEY2_H
#define _LINUX_PFKEY2_H
#include <linux/types.h>
#define PF_KEY_V2 2
#define PFKEYV2_REVISION 199806L
struct sadb_msg {
__u8 sadb_msg_version;
__u8 sadb_msg_type;
__u8 sadb_msg_errno;
__u8 sadb_msg_satype;
__u16 sadb_msg_len;
__u16 sadb_msg_reserved;
__u32 sadb_msg_seq;
__u32 sadb_msg_pid;
} __attribute__((packed));
/* sizeof(struct sadb_msg) == 16 */
struct sadb_ext {
__u16 sadb_ext_len;
__u16 sadb_ext_type;
} __attribute__((packed));
/* sizeof(struct sadb_ext) == 4 */
struct sadb_sa {
__u16 sadb_sa_len;
__u16 sadb_sa_exttype;
__be32 sadb_sa_spi;
__u8 sadb_sa_replay;
__u8 sadb_sa_state;
__u8 sadb_sa_auth;
__u8 sadb_sa_encrypt;
__u32 sadb_sa_flags;
} __attribute__((packed));
/* sizeof(struct sadb_sa) == 16 */
struct sadb_lifetime {
__u16 sadb_lifetime_len;
__u16 sadb_lifetime_exttype;
__u32 sadb_lifetime_allocations;
__u64 sadb_lifetime_bytes;
__u64 sadb_lifetime_addtime;
__u64 sadb_lifetime_usetime;
} __attribute__((packed));
/* sizeof(struct sadb_lifetime) == 32 */
struct sadb_address {
__u16 sadb_address_len;
__u16 sadb_address_exttype;
__u8 sadb_address_proto;
__u8 sadb_address_prefixlen;
__u16 sadb_address_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_address) == 8 */
struct sadb_key {
__u16 sadb_key_len;
__u16 sadb_key_exttype;
__u16 sadb_key_bits;
__u16 sadb_key_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_key) == 8 */
struct sadb_ident {
__u16 sadb_ident_len;
__u16 sadb_ident_exttype;
__u16 sadb_ident_type;
__u16 sadb_ident_reserved;
__u64 sadb_ident_id;
} __attribute__((packed));
/* sizeof(struct sadb_ident) == 16 */
struct sadb_sens {
__u16 sadb_sens_len;
__u16 sadb_sens_exttype;
__u32 sadb_sens_dpd;
__u8 sadb_sens_sens_level;
__u8 sadb_sens_sens_len;
__u8 sadb_sens_integ_level;
__u8 sadb_sens_integ_len;
__u32 sadb_sens_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_sens) == 16 */
/* followed by:
__u64 sadb_sens_bitmap[sens_len];
__u64 sadb_integ_bitmap[integ_len]; */
struct sadb_prop {
__u16 sadb_prop_len;
__u16 sadb_prop_exttype;
__u8 sadb_prop_replay;
__u8 sadb_prop_reserved[3];
} __attribute__((packed));
/* sizeof(struct sadb_prop) == 8 */
/* followed by:
struct sadb_comb sadb_combs[(sadb_prop_len +
sizeof(__u64) - sizeof(struct sadb_prop)) /
sizeof(struct sadb_comb)]; */
struct sadb_comb {
__u8 sadb_comb_auth;
__u8 sadb_comb_encrypt;
__u16 sadb_comb_flags;
__u16 sadb_comb_auth_minbits;
__u16 sadb_comb_auth_maxbits;
__u16 sadb_comb_encrypt_minbits;
__u16 sadb_comb_encrypt_maxbits;
__u32 sadb_comb_reserved;
__u32 sadb_comb_soft_allocations;
__u32 sadb_comb_hard_allocations;
__u64 sadb_comb_soft_bytes;
__u64 sadb_comb_hard_bytes;
__u64 sadb_comb_soft_addtime;
__u64 sadb_comb_hard_addtime;
__u64 sadb_comb_soft_usetime;
__u64 sadb_comb_hard_usetime;
} __attribute__((packed));
/* sizeof(struct sadb_comb) == 72 */
struct sadb_supported {
__u16 sadb_supported_len;
__u16 sadb_supported_exttype;
__u32 sadb_supported_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_supported) == 8 */
/* followed by:
struct sadb_alg sadb_algs[(sadb_supported_len +
sizeof(__u64) - sizeof(struct sadb_supported)) /
sizeof(struct sadb_alg)]; */
struct sadb_alg {
__u8 sadb_alg_id;
__u8 sadb_alg_ivlen;
__u16 sadb_alg_minbits;
__u16 sadb_alg_maxbits;
__u16 sadb_alg_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_alg) == 8 */
struct sadb_spirange {
__u16 sadb_spirange_len;
__u16 sadb_spirange_exttype;
__u32 sadb_spirange_min;
__u32 sadb_spirange_max;
__u32 sadb_spirange_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_spirange) == 16 */
struct sadb_x_kmprivate {
__u16 sadb_x_kmprivate_len;
__u16 sadb_x_kmprivate_exttype;
__u32 sadb_x_kmprivate_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_x_kmprivate) == 8 */
struct sadb_x_sa2 {
__u16 sadb_x_sa2_len;
__u16 sadb_x_sa2_exttype;
__u8 sadb_x_sa2_mode;
__u8 sadb_x_sa2_reserved1;
__u16 sadb_x_sa2_reserved2;
__u32 sadb_x_sa2_sequence;
__u32 sadb_x_sa2_reqid;
} __attribute__((packed));
/* sizeof(struct sadb_x_sa2) == 16 */
struct sadb_x_policy {
__u16 sadb_x_policy_len;
__u16 sadb_x_policy_exttype;
__u16 sadb_x_policy_type;
__u8 sadb_x_policy_dir;
__u8 sadb_x_policy_reserved;
__u32 sadb_x_policy_id;
__u32 sadb_x_policy_priority;
} __attribute__((packed));
/* sizeof(struct sadb_x_policy) == 16 */
struct sadb_x_ipsecrequest {
__u16 sadb_x_ipsecrequest_len;
__u16 sadb_x_ipsecrequest_proto;
__u8 sadb_x_ipsecrequest_mode;
__u8 sadb_x_ipsecrequest_level;
__u16 sadb_x_ipsecrequest_reserved1;
__u32 sadb_x_ipsecrequest_reqid;
__u32 sadb_x_ipsecrequest_reserved2;
} __attribute__((packed));
/* sizeof(struct sadb_x_ipsecrequest) == 16 */
/* This defines the TYPE of Nat Traversal in use. Currently only one
* type of NAT-T is supported, draft-ietf-ipsec-udp-encaps-06
*/
struct sadb_x_nat_t_type {
__u16 sadb_x_nat_t_type_len;
__u16 sadb_x_nat_t_type_exttype;
__u8 sadb_x_nat_t_type_type;
__u8 sadb_x_nat_t_type_reserved[3];
} __attribute__((packed));
/* sizeof(struct sadb_x_nat_t_type) == 8 */
/* Pass a NAT Traversal port (Source or Dest port) */
struct sadb_x_nat_t_port {
__u16 sadb_x_nat_t_port_len;
__u16 sadb_x_nat_t_port_exttype;
__be16 sadb_x_nat_t_port_port;
__u16 sadb_x_nat_t_port_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_x_nat_t_port) == 8 */
/* Generic LSM security context */
struct sadb_x_sec_ctx {
__u16 sadb_x_sec_len;
__u16 sadb_x_sec_exttype;
__u8 sadb_x_ctx_alg; /* LSMs: e.g., selinux == 1 */
__u8 sadb_x_ctx_doi;
__u16 sadb_x_ctx_len;
} __attribute__((packed));
/* sizeof(struct sadb_sec_ctx) = 8 */
/* Used by MIGRATE to pass addresses IKE will use to perform
* negotiation with the peer */
struct sadb_x_kmaddress {
__u16 sadb_x_kmaddress_len;
__u16 sadb_x_kmaddress_exttype;
__u32 sadb_x_kmaddress_reserved;
} __attribute__((packed));
/* sizeof(struct sadb_x_kmaddress) == 8 */
/* To specify the SA dump filter */
struct sadb_x_filter {
__u16 sadb_x_filter_len;
__u16 sadb_x_filter_exttype;
__u32 sadb_x_filter_saddr[4];
__u32 sadb_x_filter_daddr[4];
__u16 sadb_x_filter_family;
__u8 sadb_x_filter_splen;
__u8 sadb_x_filter_dplen;
} __attribute__((packed));
/* sizeof(struct sadb_x_filter) == 40 */
/* Message types */
#define SADB_RESERVED 0
#define SADB_GETSPI 1
#define SADB_UPDATE 2
#define SADB_ADD 3
#define SADB_DELETE 4
#define SADB_GET 5
#define SADB_ACQUIRE 6
#define SADB_REGISTER 7
#define SADB_EXPIRE 8
#define SADB_FLUSH 9
#define SADB_DUMP 10
#define SADB_X_PROMISC 11
#define SADB_X_PCHANGE 12
#define SADB_X_SPDUPDATE 13
#define SADB_X_SPDADD 14
#define SADB_X_SPDDELETE 15
#define SADB_X_SPDGET 16
#define SADB_X_SPDACQUIRE 17
#define SADB_X_SPDDUMP 18
#define SADB_X_SPDFLUSH 19
#define SADB_X_SPDSETIDX 20
#define SADB_X_SPDEXPIRE 21
#define SADB_X_SPDDELETE2 22
#define SADB_X_NAT_T_NEW_MAPPING 23
#define SADB_X_MIGRATE 24
#define SADB_MAX 24
/* Security Association flags */
#define SADB_SAFLAGS_PFS 1
#define SADB_SAFLAGS_NOPMTUDISC 0x20000000
#define SADB_SAFLAGS_DECAP_DSCP 0x40000000
#define SADB_SAFLAGS_NOECN 0x80000000
/* Security Association states */
#define SADB_SASTATE_LARVAL 0
#define SADB_SASTATE_MATURE 1
#define SADB_SASTATE_DYING 2
#define SADB_SASTATE_DEAD 3
#define SADB_SASTATE_MAX 3
/* Security Association types */
#define SADB_SATYPE_UNSPEC 0
#define SADB_SATYPE_AH 2
#define SADB_SATYPE_ESP 3
#define SADB_SATYPE_RSVP 5
#define SADB_SATYPE_OSPFV2 6
#define SADB_SATYPE_RIPV2 7
#define SADB_SATYPE_MIP 8
#define SADB_X_SATYPE_IPCOMP 9
#define SADB_SATYPE_MAX 9
/* Authentication algorithms */
#define SADB_AALG_NONE 0
#define SADB_AALG_MD5HMAC 2
#define SADB_AALG_SHA1HMAC 3
#define SADB_X_AALG_SHA2_256HMAC 5
#define SADB_X_AALG_SHA2_384HMAC 6
#define SADB_X_AALG_SHA2_512HMAC 7
#define SADB_X_AALG_RIPEMD160HMAC 8
#define SADB_X_AALG_AES_XCBC_MAC 9
#define SADB_X_AALG_NULL 251 /* kame */
#define SADB_AALG_MAX 251
/* Encryption algorithms */
#define SADB_EALG_NONE 0
#define SADB_EALG_DESCBC 2
#define SADB_EALG_3DESCBC 3
#define SADB_X_EALG_CASTCBC 6
#define SADB_X_EALG_BLOWFISHCBC 7
#define SADB_EALG_NULL 11
#define SADB_X_EALG_AESCBC 12
#define SADB_X_EALG_AESCTR 13
#define SADB_X_EALG_AES_CCM_ICV8 14
#define SADB_X_EALG_AES_CCM_ICV12 15
#define SADB_X_EALG_AES_CCM_ICV16 16
#define SADB_X_EALG_AES_GCM_ICV8 18
#define SADB_X_EALG_AES_GCM_ICV12 19
#define SADB_X_EALG_AES_GCM_ICV16 20
#define SADB_X_EALG_CAMELLIACBC 22
#define SADB_X_EALG_NULL_AES_GMAC 23
#define SADB_EALG_MAX 253 /* last EALG */
/* private allocations should use 249-255 (RFC2407) */
#define SADB_X_EALG_SERPENTCBC 252 /* draft-ietf-ipsec-ciph-aes-cbc-00 */
#define SADB_X_EALG_TWOFISHCBC 253 /* draft-ietf-ipsec-ciph-aes-cbc-00 */
/* Compression algorithms */
#define SADB_X_CALG_NONE 0
#define SADB_X_CALG_OUI 1
#define SADB_X_CALG_DEFLATE 2
#define SADB_X_CALG_LZS 3
#define SADB_X_CALG_LZJH 4
#define SADB_X_CALG_MAX 4
/* Extension Header values */
#define SADB_EXT_RESERVED 0
#define SADB_EXT_SA 1
#define SADB_EXT_LIFETIME_CURRENT 2
#define SADB_EXT_LIFETIME_HARD 3
#define SADB_EXT_LIFETIME_SOFT 4
#define SADB_EXT_ADDRESS_SRC 5
#define SADB_EXT_ADDRESS_DST 6
#define SADB_EXT_ADDRESS_PROXY 7
#define SADB_EXT_KEY_AUTH 8
#define SADB_EXT_KEY_ENCRYPT 9
#define SADB_EXT_IDENTITY_SRC 10
#define SADB_EXT_IDENTITY_DST 11
#define SADB_EXT_SENSITIVITY 12
#define SADB_EXT_PROPOSAL 13
#define SADB_EXT_SUPPORTED_AUTH 14
#define SADB_EXT_SUPPORTED_ENCRYPT 15
#define SADB_EXT_SPIRANGE 16
#define SADB_X_EXT_KMPRIVATE 17
#define SADB_X_EXT_POLICY 18
#define SADB_X_EXT_SA2 19
/* The next four entries are for setting up NAT Traversal */
#define SADB_X_EXT_NAT_T_TYPE 20
#define SADB_X_EXT_NAT_T_SPORT 21
#define SADB_X_EXT_NAT_T_DPORT 22
#define SADB_X_EXT_NAT_T_OA 23
#define SADB_X_EXT_SEC_CTX 24
/* Used with MIGRATE to pass @ to IKE for negotiation */
#define SADB_X_EXT_KMADDRESS 25
#define SADB_X_EXT_FILTER 26
#define SADB_EXT_MAX 26
/* Identity Extension values */
#define SADB_IDENTTYPE_RESERVED 0
#define SADB_IDENTTYPE_PREFIX 1
#define SADB_IDENTTYPE_FQDN 2
#define SADB_IDENTTYPE_USERFQDN 3
#define SADB_IDENTTYPE_MAX 3
#endif /* !(_LINUX_PFKEY2_H) */

View File

@ -681,10 +681,29 @@ struct tcamsg {
unsigned char tca__pad1;
unsigned short tca__pad2;
};
enum {
TCA_ROOT_UNSPEC,
TCA_ROOT_TAB,
#define TCA_ACT_TAB TCA_ROOT_TAB
#define TCAA_MAX TCA_ROOT_TAB
TCA_ROOT_FLAGS,
TCA_ROOT_COUNT,
TCA_ROOT_TIME_DELTA, /* in msecs */
__TCA_ROOT_MAX,
#define TCA_ROOT_MAX (__TCA_ROOT_MAX - 1)
};
#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg))))
#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg))
#define TCA_ACT_TAB 1 /* attr type must be >=1 */
#define TCAA_MAX 1
/* tcamsg flags stored in attribute TCA_ROOT_FLAGS
*
* TCA_FLAG_LARGE_DUMP_ON user->kernel to request for larger than TCA_ACT_MAX_PRIO
* actions in a dump. All dump responses will contain the number of actions
* being dumped stored in for user app's consumption in TCA_ROOT_COUNT
*
*/
#define TCA_FLAG_LARGE_DUMP_ON (1 << 0)
/* New extended info filters for IFLA_EXT_MASK */
#define RTEXT_FILTER_VF (1 << 0)

View File

@ -33,6 +33,7 @@ struct seg6_iptunnel_encap {
enum {
SEG6_IPTUN_MODE_INLINE,
SEG6_IPTUN_MODE_ENCAP,
SEG6_IPTUN_MODE_L2ENCAP,
};

View File

@ -0,0 +1,68 @@
/*
* SR-IPv6 implementation
*
* Author:
* David Lebrun <david.lebrun@uclouvain.be>
*
*
* 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.
*/
#ifndef _LINUX_SEG6_LOCAL_H
#define _LINUX_SEG6_LOCAL_H
#include <linux/seg6.h>
enum {
SEG6_LOCAL_UNSPEC,
SEG6_LOCAL_ACTION,
SEG6_LOCAL_SRH,
SEG6_LOCAL_TABLE,
SEG6_LOCAL_NH4,
SEG6_LOCAL_NH6,
SEG6_LOCAL_IIF,
SEG6_LOCAL_OIF,
__SEG6_LOCAL_MAX,
};
#define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
enum {
SEG6_LOCAL_ACTION_UNSPEC = 0,
/* node segment */
SEG6_LOCAL_ACTION_END = 1,
/* adjacency segment (IPv6 cross-connect) */
SEG6_LOCAL_ACTION_END_X = 2,
/* lookup of next seg NH in table */
SEG6_LOCAL_ACTION_END_T = 3,
/* decap and L2 cross-connect */
SEG6_LOCAL_ACTION_END_DX2 = 4,
/* decap and IPv6 cross-connect */
SEG6_LOCAL_ACTION_END_DX6 = 5,
/* decap and IPv4 cross-connect */
SEG6_LOCAL_ACTION_END_DX4 = 6,
/* decap and lookup of DA in v6 table */
SEG6_LOCAL_ACTION_END_DT6 = 7,
/* decap and lookup of DA in v4 table */
SEG6_LOCAL_ACTION_END_DT4 = 8,
/* binding segment with insertion */
SEG6_LOCAL_ACTION_END_B6 = 9,
/* binding segment with encapsulation */
SEG6_LOCAL_ACTION_END_B6_ENCAP = 10,
/* binding segment with MPLS encap */
SEG6_LOCAL_ACTION_END_BM = 11,
/* lookup last seg in table */
SEG6_LOCAL_ACTION_END_S = 12,
/* forward to SR-unaware VNF with static proxy */
SEG6_LOCAL_ACTION_END_AS = 13,
/* forward to SR-unaware VNF with masquerading */
SEG6_LOCAL_ACTION_END_AM = 14,
__SEG6_LOCAL_ACTION_MAX,
};
#define SEG6_LOCAL_ACTION_MAX (__SEG6_LOCAL_ACTION_MAX - 1)
#endif

View File

@ -231,6 +231,14 @@ enum {
TCP_NLA_SNDBUF_LIMITED, /* Time (usec) limited by send buffer */
TCP_NLA_DATA_SEGS_OUT, /* Data pkts sent including retransmission */
TCP_NLA_TOTAL_RETRANS, /* Data pkts retransmitted */
TCP_NLA_PACING_RATE, /* Pacing rate in bytes per second */
TCP_NLA_DELIVERY_RATE, /* Delivery rate in bytes per second */
TCP_NLA_SND_CWND, /* Sending congestion window */
TCP_NLA_REORDERING, /* Reordering metric */
TCP_NLA_MIN_RTT, /* minimum RTT */
TCP_NLA_RECUR_RETRANS, /* Recurring retransmits for the current pkt */
TCP_NLA_DELIVERY_RATE_APP_LMT, /* delivery rate application limited ? */
};
/* for TCP_MD5SIG socket option */
@ -248,4 +256,13 @@ struct tcp_md5sig {
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
};
/* INET_DIAG_MD5SIG */
struct tcp_diag_md5sig {
__u8 tcpm_family;
__u8 tcpm_prefixlen;
__u16 tcpm_keylen;
__be32 tcpm_addr[4];
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN];
};
#endif /* _LINUX_TCP_H */

View File

@ -304,6 +304,7 @@ enum xfrm_attr_type_t {
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
XFRMA_PAD,
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
XFRMA_OUTPUT_MARK, /* __u32 */
__XFRMA_MAX
#define XFRMA_MAX (__XFRMA_MAX - 1)

View File

@ -20,6 +20,7 @@ extern int show_raw;
extern int resolve_hosts;
extern int oneline;
extern int brief;
extern int json;
extern int timestamp;
extern int timestamp_short;
extern const char * _SL_;

View File

@ -9,24 +9,11 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
ipvrf.o iplink_xstats.o ipseg6.o
ipvrf.o iplink_xstats.o ipseg6.o ip_print.o
RTMONOBJ=rtmon.o
include ../Config
ifeq ($(IP_CONFIG_SETNS),y)
CFLAGS += -DHAVE_SETNS
endif
ifeq ($(HAVE_ELF),y)
CFLAGS += -DHAVE_ELF
LDLIBS += -lelf
endif
ifeq ($(HAVE_MNL),y)
CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags)
LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)
endif
include ../config.mk
ALLOBJ=$(IPOBJ) $(RTMONOBJ)
SCRIPTS=ifcfg rtpr routel routef

View File

@ -33,6 +33,7 @@ int show_details;
int resolve_hosts;
int oneline;
int brief;
int json;
int timestamp;
const char *_SL_;
int force;
@ -258,6 +259,8 @@ int main(int argc, char **argv)
batch_file = argv[1];
} else if (matches(opt, "-brief") == 0) {
++brief;
} else if (matches(opt, "-json") == 0) {
++json;
} else if (matches(opt, "-rcvbuf") == 0) {
unsigned int size;
@ -292,6 +295,9 @@ int main(int argc, char **argv)
_SL_ = oneline ? "\\" : "\n";
if (json)
check_if_color_enabled();
if (batch_file)
return batch(batch_file);

View File

@ -140,3 +140,59 @@ int name_is_vrf(const char *name);
#endif
void print_num(FILE *fp, unsigned int width, uint64_t count);
#include "json_writer.h"
json_writer_t *get_json_writer(void);
/*
* use:
* - PRINT_ANY for context based output
* - PRINT_FP for non json specific output
* - PRINT_JSON for json specific output
*/
enum output_type {
PRINT_FP = 1,
PRINT_JSON = 2,
PRINT_ANY = 4,
};
void new_json_obj(int json, FILE *fp);
void delete_json_obj(void);
bool is_json_context(void);
void set_current_fp(FILE *fp);
void fflush_fp(void);
void open_json_object(const char *str);
void close_json_object(void);
void open_json_array(enum output_type type, const char *delim);
void close_json_array(enum output_type type, const char *delim);
#include "color.h"
#define _PRINT_FUNC(type_name, type) \
void print_color_##type_name(enum output_type t, \
enum color_attr color, \
const char *key, \
const char *fmt, \
type value); \
\
static inline void print_##type_name(enum output_type t, \
const char *key, \
const char *fmt, \
type value) \
{ \
print_color_##type_name(t, -1, key, fmt, value); \
}
_PRINT_FUNC(int, int);
_PRINT_FUNC(bool, bool);
_PRINT_FUNC(null, const char*);
_PRINT_FUNC(string, const char*);
_PRINT_FUNC(uint, uint64_t);
_PRINT_FUNC(hu, unsigned short);
_PRINT_FUNC(hex, unsigned int);
_PRINT_FUNC(0xhex, unsigned int);
_PRINT_FUNC(lluint, unsigned long long int);
#undef _PRINT_FUNC

233
ip/ip_print.c Normal file
View File

@ -0,0 +1,233 @@
/*
* ip_print.c "ip print regular or json output".
*
* 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.
*
* Authors: Julien Fortin, <julien@cumulusnetworks.com>
*
*/
#include <stdarg.h>
#include <stdio.h>
#include "utils.h"
#include "ip_common.h"
#include "json_writer.h"
static json_writer_t *_jw;
static FILE *_fp;
#define _IS_JSON_CONTEXT(type) ((type & PRINT_JSON || type & PRINT_ANY) && _jw)
#define _IS_FP_CONTEXT(type) (!_jw && (type & PRINT_FP || type & PRINT_ANY))
void new_json_obj(int json, FILE *fp)
{
if (json) {
_jw = jsonw_new(fp);
if (!_jw) {
perror("json object");
exit(1);
}
jsonw_pretty(_jw, true);
jsonw_start_array(_jw);
}
set_current_fp(fp);
}
void delete_json_obj(void)
{
if (_jw) {
jsonw_end_array(_jw);
jsonw_destroy(&_jw);
}
}
bool is_json_context(void)
{
return _jw != NULL;
}
void set_current_fp(FILE *fp)
{
if (!fp) {
fprintf(stderr, "Error: invalid file pointer.\n");
exit(1);
}
_fp = fp;
}
json_writer_t *get_json_writer(void)
{
return _jw;
}
void open_json_object(const char *str)
{
if (_IS_JSON_CONTEXT(PRINT_JSON)) {
if (str)
jsonw_name(_jw, str);
jsonw_start_object(_jw);
}
}
void close_json_object(void)
{
if (_IS_JSON_CONTEXT(PRINT_JSON))
jsonw_end_object(_jw);
}
/*
* Start json array or string array using
* the provided string as json key (if not null)
* or as array delimiter in non-json context.
*/
void open_json_array(enum output_type type, const char *str)
{
if (_IS_JSON_CONTEXT(type)) {
if (str)
jsonw_name(_jw, str);
jsonw_start_array(_jw);
} else if (_IS_FP_CONTEXT(type)) {
fprintf(_fp, "%s", str);
}
}
/*
* End json array or string array
*/
void close_json_array(enum output_type type, const char *str)
{
if (_IS_JSON_CONTEXT(type)) {
jsonw_pretty(_jw, false);
jsonw_end_array(_jw);
jsonw_pretty(_jw, true);
} else if (_IS_FP_CONTEXT(type)) {
fprintf(_fp, "%s", str);
}
}
/*
* pre-processor directive to generate similar
* functions handling different types
*/
#define _PRINT_FUNC(type_name, type) \
void print_color_##type_name(enum output_type t, \
enum color_attr color, \
const char *key, \
const char *fmt, \
type value) \
{ \
if (_IS_JSON_CONTEXT(t)) { \
if (!key) \
jsonw_##type_name(_jw, value); \
else \
jsonw_##type_name##_field(_jw, key, value); \
} else if (_IS_FP_CONTEXT(t)) { \
color_fprintf(_fp, color, fmt, value); \
} \
}
_PRINT_FUNC(int, int);
_PRINT_FUNC(hu, unsigned short);
_PRINT_FUNC(uint, uint64_t);
_PRINT_FUNC(lluint, unsigned long long int);
#undef _PRINT_FUNC
void print_color_string(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
const char *value)
{
if (_IS_JSON_CONTEXT(type)) {
if (key && !value)
jsonw_name(_jw, key);
else if (!key && value)
jsonw_string(_jw, value);
else
jsonw_string_field(_jw, key, value);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(_fp, color, fmt, value);
}
}
/*
* value's type is bool. When using this function in FP context you can't pass
* a value to it, you will need to use "is_json_context()" to have different
* branch for json and regular output. grep -r "print_bool" for example
*/
void print_color_bool(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
bool value)
{
if (_IS_JSON_CONTEXT(type)) {
if (key)
jsonw_bool_field(_jw, key, value);
else
jsonw_bool(_jw, value);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(_fp, color, fmt, value ? "true" : "false");
}
}
/*
* In JSON context uses hardcode %#x format: 42 -> 0x2a
*/
void print_color_0xhex(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
unsigned int hex)
{
if (_IS_JSON_CONTEXT(type)) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "%#x", hex);
print_string(PRINT_JSON, key, NULL, b1);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(_fp, color, fmt, hex);
}
}
void print_color_hex(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
unsigned int hex)
{
if (_IS_JSON_CONTEXT(type)) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "%x", hex);
if (key)
jsonw_string_field(_jw, key, b1);
else
jsonw_string(_jw, b1);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(_fp, color, fmt, hex);
}
}
/*
* In JSON context we don't use the argument "value" we simply call jsonw_null
* whereas FP context can use "value" to output anything
*/
void print_color_null(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
const char *value)
{
if (_IS_JSON_CONTEXT(type)) {
if (key)
jsonw_null_field(_jw, key);
else
jsonw_null(_jw);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(_fp, color, fmt, value);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -112,8 +112,9 @@ void iplink_usage(void)
"\n"
"TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"
" bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
" gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave |\n"
" bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n");
" gre | gretap | erspan | ip6gre | ip6gretap | vti | nlmon |\n"
" team_slave | bond_slave | ipvlan | geneve | bridge_slave |\n"
" vrf | macsec }\n");
}
exit(-1);
}
@ -1046,10 +1047,12 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
return -2;
}
open_json_object(NULL);
if (brief)
print_linkinfo_brief(NULL, &answer.n, stdout, NULL);
else
print_linkinfo(NULL, &answer.n, stdout);
close_json_object();
return 0;
}

View File

@ -376,8 +376,8 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if (tb[IFLA_BOND_MODE]) {
const char *mode = get_name(mode_tbl,
rta_getattr_u8(tb[IFLA_BOND_MODE]));
fprintf(f, "mode %s ", mode);
rta_getattr_u8(tb[IFLA_BOND_MODE]));
print_string(PRINT_ANY, "mode", "mode %s ", mode);
}
if (tb[IFLA_BOND_ACTIVE_SLAVE] &&
@ -386,61 +386,97 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
const char *n = if_indextoname(ifindex, buf);
if (n)
fprintf(f, "active_slave %s ", n);
print_string(PRINT_ANY,
"active_slave",
"active_slave %s ",
n);
else
fprintf(f, "active_slave %u ", ifindex);
print_uint(PRINT_ANY,
"active_slave_index",
"active_slave %u ",
ifindex);
}
if (tb[IFLA_BOND_MIIMON])
fprintf(f, "miimon %u ", rta_getattr_u32(tb[IFLA_BOND_MIIMON]));
print_uint(PRINT_ANY,
"miimon",
"miimon %u ",
rta_getattr_u32(tb[IFLA_BOND_MIIMON]));
if (tb[IFLA_BOND_UPDELAY])
fprintf(f, "updelay %u ", rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));
print_uint(PRINT_ANY,
"updelay",
"updelay %u ",
rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));
if (tb[IFLA_BOND_DOWNDELAY])
fprintf(f, "downdelay %u ",
rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
print_uint(PRINT_ANY,
"downdelay",
"downdelay %u ",
rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
if (tb[IFLA_BOND_USE_CARRIER])
fprintf(f, "use_carrier %u ",
rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));
print_uint(PRINT_ANY,
"use_carrier",
"use_carrier %u ",
rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));
if (tb[IFLA_BOND_ARP_INTERVAL])
fprintf(f, "arp_interval %u ",
rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));
print_uint(PRINT_ANY,
"arp_interval",
"arp_interval %u ",
rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));
if (tb[IFLA_BOND_ARP_IP_TARGET]) {
struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1];
int i;
parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS,
tb[IFLA_BOND_ARP_IP_TARGET]);
tb[IFLA_BOND_ARP_IP_TARGET]);
if (iptb[0])
fprintf(f, "arp_ip_target ");
if (iptb[0]) {
open_json_array(PRINT_JSON, "arp_ip_target");
print_string(PRINT_FP, NULL, "arp_ip_target ", NULL);
}
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
if (iptb[i])
fprintf(f, "%s",
rt_addr_n2a_rta(AF_INET, iptb[i]));
if (i < BOND_MAX_ARP_TARGETS-1 && iptb[i+1])
print_string(PRINT_ANY,
NULL,
"%s",
rt_addr_n2a_rta(AF_INET, iptb[i]));
if (!is_json_context()
&& i < BOND_MAX_ARP_TARGETS-1
&& iptb[i+1])
fprintf(f, ",");
}
if (iptb[0])
fprintf(f, " ");
if (iptb[0]) {
print_string(PRINT_FP, NULL, " ", NULL);
close_json_array(PRINT_JSON, NULL);
}
}
if (tb[IFLA_BOND_ARP_VALIDATE]) {
const char *arp_validate = get_name(arp_validate_tbl,
rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE]));
fprintf(f, "arp_validate %s ", arp_validate);
__u32 arp_v = rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE]);
const char *arp_validate = get_name(arp_validate_tbl, arp_v);
if (!arp_v && is_json_context())
print_null(PRINT_JSON, "arp_validate", NULL, NULL);
else
print_string(PRINT_ANY,
"arp_validate",
"arp_validate %s ",
arp_validate);
}
if (tb[IFLA_BOND_ARP_ALL_TARGETS]) {
const char *arp_all_targets = get_name(arp_all_targets_tbl,
rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]));
fprintf(f, "arp_all_targets %s ", arp_all_targets);
rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]));
print_string(PRINT_ANY,
"arp_all_targets",
"arp_all_targets %s ",
arp_all_targets);
}
if (tb[IFLA_BOND_PRIMARY] &&
@ -449,123 +485,176 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
const char *n = if_indextoname(ifindex, buf);
if (n)
fprintf(f, "primary %s ", n);
print_string(PRINT_ANY, "primary", "primary %s ", n);
else
fprintf(f, "primary %u ", ifindex);
print_uint(PRINT_ANY,
"primary_index",
"primary %u ",
ifindex);
}
if (tb[IFLA_BOND_PRIMARY_RESELECT]) {
const char *primary_reselect = get_name(primary_reselect_tbl,
rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT]));
fprintf(f, "primary_reselect %s ", primary_reselect);
rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT]));
print_string(PRINT_ANY,
"primary_reselect",
"primary_reselect %s ",
primary_reselect);
}
if (tb[IFLA_BOND_FAIL_OVER_MAC]) {
const char *fail_over_mac = get_name(fail_over_mac_tbl,
rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC]));
fprintf(f, "fail_over_mac %s ", fail_over_mac);
rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC]));
print_string(PRINT_ANY,
"fail_over_mac",
"fail_over_mac %s ",
fail_over_mac);
}
if (tb[IFLA_BOND_XMIT_HASH_POLICY]) {
const char *xmit_hash_policy = get_name(xmit_hash_policy_tbl,
rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]));
fprintf(f, "xmit_hash_policy %s ", xmit_hash_policy);
rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]));
print_string(PRINT_ANY,
"xmit_hash_policy",
"xmit_hash_policy %s ",
xmit_hash_policy);
}
if (tb[IFLA_BOND_RESEND_IGMP])
fprintf(f, "resend_igmp %u ",
rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP]));
print_uint(PRINT_ANY,
"resend_igmp",
"resend_igmp %u ",
rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP]));
if (tb[IFLA_BOND_NUM_PEER_NOTIF])
fprintf(f, "num_grat_arp %u ",
rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]));
print_uint(PRINT_ANY,
"num_peer_notif",
"num_grat_arp %u ",
rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]));
if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE])
fprintf(f, "all_slaves_active %u ",
rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]));
print_uint(PRINT_ANY,
"all_slaves_active",
"all_slaves_active %u ",
rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]));
if (tb[IFLA_BOND_MIN_LINKS])
fprintf(f, "min_links %u ",
rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS]));
print_uint(PRINT_ANY,
"min_links",
"min_links %u ",
rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS]));
if (tb[IFLA_BOND_LP_INTERVAL])
fprintf(f, "lp_interval %u ",
rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL]));
print_uint(PRINT_ANY,
"lp_interval",
"lp_interval %u ",
rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL]));
if (tb[IFLA_BOND_PACKETS_PER_SLAVE])
fprintf(f, "packets_per_slave %u ",
rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));
print_uint(PRINT_ANY,
"packets_per_slave",
"packets_per_slave %u ",
rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));
if (tb[IFLA_BOND_AD_LACP_RATE]) {
const char *lacp_rate = get_name(lacp_rate_tbl,
rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE]));
fprintf(f, "lacp_rate %s ", lacp_rate);
rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE]));
print_string(PRINT_ANY,
"ad_lacp_rate",
"lacp_rate %s ",
lacp_rate);
}
if (tb[IFLA_BOND_AD_SELECT]) {
const char *ad_select = get_name(ad_select_tbl,
rta_getattr_u8(tb[IFLA_BOND_AD_SELECT]));
fprintf(f, "ad_select %s ", ad_select);
rta_getattr_u8(tb[IFLA_BOND_AD_SELECT]));
print_string(PRINT_ANY,
"ad_select",
"ad_select %s ",
ad_select);
}
if (tb[IFLA_BOND_AD_INFO]) {
struct rtattr *adtb[IFLA_BOND_AD_INFO_MAX + 1];
parse_rtattr_nested(adtb, IFLA_BOND_AD_INFO_MAX,
tb[IFLA_BOND_AD_INFO]);
tb[IFLA_BOND_AD_INFO]);
open_json_object("ad_info");
if (adtb[IFLA_BOND_AD_INFO_AGGREGATOR])
fprintf(f, "ad_aggregator %d ",
rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR]));
print_int(PRINT_ANY,
"aggregator",
"ad_aggregator %d ",
rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR]));
if (adtb[IFLA_BOND_AD_INFO_NUM_PORTS])
fprintf(f, "ad_num_ports %d ",
rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS]));
print_int(PRINT_ANY,
"num_ports",
"ad_num_ports %d ",
rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS]));
if (adtb[IFLA_BOND_AD_INFO_ACTOR_KEY])
fprintf(f, "ad_actor_key %d ",
rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]));
print_int(PRINT_ANY,
"actor_key",
"ad_actor_key %d ",
rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]));
if (adtb[IFLA_BOND_AD_INFO_PARTNER_KEY])
fprintf(f, "ad_partner_key %d ",
rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]));
print_int(PRINT_ANY,
"partner_key",
"ad_partner_key %d ",
rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]));
if (adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]) {
unsigned char *p =
RTA_DATA(adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]);
SPRINT_BUF(b);
fprintf(f, "ad_partner_mac %s ",
ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
print_string(PRINT_ANY,
"partner_mac",
"ad_partner_mac %s ",
ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
}
close_json_object();
}
if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
fprintf(f, "ad_actor_sys_prio %u ",
rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
print_uint(PRINT_ANY,
"ad_actor_sys_prio",
"ad_actor_sys_prio %u ",
rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
}
if (tb[IFLA_BOND_AD_USER_PORT_KEY]) {
fprintf(f, "ad_user_port_key %u ",
rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
print_uint(PRINT_ANY,
"ad_user_port_key",
"ad_user_port_key %u ",
rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
}
if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) {
/* We assume the l2 address is an Ethernet MAC address */
SPRINT_BUF(b1);
fprintf(f, "ad_actor_system %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
1 /*ARPHDR_ETHER*/, b1, sizeof(b1)));
print_string(PRINT_ANY,
"ad_actor_system",
"ad_actor_system %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
1 /*ARPHDR_ETHER*/, b1, sizeof(b1)));
}
if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) {
fprintf(f, "tlb_dynamic_lb %u ",
rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]));
print_uint(PRINT_ANY,
"tlb_dynamic_lb",
"tlb_dynamic_lb %u ",
rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]));
}
}
static void bond_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
print_explain(f);
}

View File

@ -37,9 +37,12 @@ static void print_slave_state(FILE *f, struct rtattr *tb)
unsigned int state = rta_getattr_u8(tb);
if (state >= ARRAY_SIZE(slave_states))
fprintf(f, "state %d ", state);
print_int(PRINT_ANY, "state_index", "state %d ", state);
else
fprintf(f, "state %s ", slave_states[state]);
print_string(PRINT_ANY,
"state",
"state %s ",
slave_states[state]);
}
static const char *slave_mii_status[] = {
@ -54,9 +57,15 @@ static void print_slave_mii_status(FILE *f, struct rtattr *tb)
unsigned int status = rta_getattr_u8(tb);
if (status >= ARRAY_SIZE(slave_mii_status))
fprintf(f, "mii_status %d ", status);
print_int(PRINT_ANY,
"mii_status_index",
"mii_status %d ",
status);
else
fprintf(f, "mii_status %s ", slave_mii_status[status]);
print_string(PRINT_ANY,
"mii_status",
"mii_status %s ",
slave_mii_status[status]);
}
static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
@ -72,30 +81,42 @@ static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *t
print_slave_mii_status(f, tb[IFLA_BOND_SLAVE_MII_STATUS]);
if (tb[IFLA_BOND_SLAVE_LINK_FAILURE_COUNT])
fprintf(f, "link_failure_count %d ",
rta_getattr_u32(tb[IFLA_BOND_SLAVE_LINK_FAILURE_COUNT]));
print_int(PRINT_ANY,
"link_failure_count",
"link_failure_count %d ",
rta_getattr_u32(tb[IFLA_BOND_SLAVE_LINK_FAILURE_COUNT]));
if (tb[IFLA_BOND_SLAVE_PERM_HWADDR])
fprintf(f, "perm_hwaddr %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
RTA_PAYLOAD(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
0, b1, sizeof(b1)));
print_string(PRINT_ANY,
"perm_hwaddr",
"perm_hwaddr %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
RTA_PAYLOAD(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
0, b1, sizeof(b1)));
if (tb[IFLA_BOND_SLAVE_QUEUE_ID])
fprintf(f, "queue_id %d ",
rta_getattr_u16(tb[IFLA_BOND_SLAVE_QUEUE_ID]));
print_int(PRINT_ANY,
"queue_id",
"queue_id %d ",
rta_getattr_u16(tb[IFLA_BOND_SLAVE_QUEUE_ID]));
if (tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID])
fprintf(f, "ad_aggregator_id %d ",
rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID]));
print_int(PRINT_ANY,
"ad_aggregator_id",
"ad_aggregator_id %d ",
rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID]));
if (tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE])
fprintf(f, "ad_actor_oper_port_state %d ",
rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]));
print_int(PRINT_ANY,
"ad_actor_oper_port_state",
"ad_actor_oper_port_state %d ",
rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]));
if (tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE])
fprintf(f, "ad_partner_oper_port_state %d ",
rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]));
print_int(PRINT_ANY,
"ad_partner_oper_port_state",
"ad_partner_oper_port_state %d ",
rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]));
}
static int bond_slave_parse_opt(struct link_util *lu, int argc, char **argv,

View File

@ -373,45 +373,81 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
return 0;
}
static void _bridge_print_timer(FILE *f,
const char *attr,
struct rtattr *timer)
{
struct timeval tv;
__jiffies_to_tv(&tv, rta_getattr_u64(timer));
if (is_json_context()) {
json_writer_t *jw = get_json_writer();
jsonw_name(jw, attr);
jsonw_printf(jw, "%i.%.2i",
(int)tv.tv_sec,
(int)tv.tv_usec / 10000);
} else {
fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec,
(int)tv.tv_usec / 10000);
}
}
static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
if (!tb)
return;
if (tb[IFLA_BR_FORWARD_DELAY])
fprintf(f, "forward_delay %u ",
rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
print_uint(PRINT_ANY,
"forward_delay",
"forward_delay %u ",
rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
if (tb[IFLA_BR_HELLO_TIME])
fprintf(f, "hello_time %u ",
rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
print_uint(PRINT_ANY,
"hello_time",
"hello_time %u ",
rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
if (tb[IFLA_BR_MAX_AGE])
fprintf(f, "max_age %u ",
rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
print_uint(PRINT_ANY,
"max_age",
"max_age %u ",
rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
if (tb[IFLA_BR_AGEING_TIME])
fprintf(f, "ageing_time %u ",
rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
print_uint(PRINT_ANY,
"ageing_time",
"ageing_time %u ",
rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
if (tb[IFLA_BR_STP_STATE])
fprintf(f, "stp_state %u ",
rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
print_uint(PRINT_ANY,
"stp_state",
"stp_state %u ",
rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
if (tb[IFLA_BR_PRIORITY])
fprintf(f, "priority %u ",
rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
print_uint(PRINT_ANY,
"priority",
"priority %u ",
rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
if (tb[IFLA_BR_VLAN_FILTERING])
fprintf(f, "vlan_filtering %u ",
rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
print_uint(PRINT_ANY,
"vlan_filtering",
"vlan_filtering %u ",
rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
if (tb[IFLA_BR_VLAN_PROTOCOL]) {
SPRINT_BUF(b1);
fprintf(f, "vlan_protocol %s ",
ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
b1, sizeof(b1)));
print_string(PRINT_ANY,
"vlan_protocol",
"vlan_protocol %s ",
ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
b1, sizeof(b1)));
}
if (tb[IFLA_BR_BRIDGE_ID]) {
@ -419,7 +455,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
sizeof(bridge_id));
fprintf(f, "bridge_id %s ", bridge_id);
print_string(PRINT_ANY,
"bridge_id",
"bridge_id %s ",
bridge_id);
}
if (tb[IFLA_BR_ROOT_ID]) {
@ -427,163 +466,201 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
sizeof(root_id));
fprintf(f, "designated_root %s ", root_id);
print_string(PRINT_ANY,
"root_id",
"designated_root %s ",
root_id);
}
if (tb[IFLA_BR_ROOT_PORT])
fprintf(f, "root_port %u ",
rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
print_uint(PRINT_ANY,
"root_port",
"root_port %u ",
rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
if (tb[IFLA_BR_ROOT_PATH_COST])
fprintf(f, "root_path_cost %u ",
rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
print_uint(PRINT_ANY,
"root_path_cost",
"root_path_cost %u ",
rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
if (tb[IFLA_BR_TOPOLOGY_CHANGE])
fprintf(f, "topology_change %u ",
rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
print_uint(PRINT_ANY,
"topology_change",
"topology_change %u ",
rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
fprintf(f, "topology_change_detected %u ",
rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
print_uint(PRINT_ANY,
"topology_change_detected",
"topology_change_detected %u ",
rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
if (tb[IFLA_BR_HELLO_TIMER]) {
struct timeval tv;
if (tb[IFLA_BR_HELLO_TIMER])
_bridge_print_timer(f, "hello_timer", tb[IFLA_BR_HELLO_TIMER]);
__jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER]));
fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
}
if (tb[IFLA_BR_TCN_TIMER])
_bridge_print_timer(f, "tcn_timer", tb[IFLA_BR_TCN_TIMER]);
if (tb[IFLA_BR_TCN_TIMER]) {
struct timeval tv;
if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER])
_bridge_print_timer(f, "topology_change_timer",
tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
__jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER]));
fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
}
if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) {
unsigned long jiffies;
struct timeval tv;
jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
__jiffies_to_tv(&tv, jiffies);
fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
}
if (tb[IFLA_BR_GC_TIMER]) {
struct timeval tv;
__jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER]));
fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
}
if (tb[IFLA_BR_GC_TIMER])
_bridge_print_timer(f, "gc_timer", tb[IFLA_BR_GC_TIMER]);
if (tb[IFLA_BR_VLAN_DEFAULT_PVID])
fprintf(f, "vlan_default_pvid %u ",
rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
print_uint(PRINT_ANY,
"vlan_default_pvid",
"vlan_default_pvid %u ",
rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
if (tb[IFLA_BR_VLAN_STATS_ENABLED])
fprintf(f, "vlan_stats_enabled %u ",
rta_getattr_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]));
print_uint(PRINT_ANY,
"vlan_stats_enabled",
"vlan_stats_enabled %u ",
rta_getattr_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]));
if (tb[IFLA_BR_GROUP_FWD_MASK])
fprintf(f, "group_fwd_mask %#x ",
rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
print_0xhex(PRINT_ANY,
"group_fwd_mask",
"group_fwd_mask %#x ",
rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
if (tb[IFLA_BR_GROUP_ADDR]) {
SPRINT_BUF(mac);
fprintf(f, "group_address %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
print_string(PRINT_ANY,
"group_addr",
"group_address %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
}
if (tb[IFLA_BR_MCAST_SNOOPING])
fprintf(f, "mcast_snooping %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
print_uint(PRINT_ANY,
"mcast_snooping",
"mcast_snooping %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
if (tb[IFLA_BR_MCAST_ROUTER])
fprintf(f, "mcast_router %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
print_uint(PRINT_ANY,
"mcast_router",
"mcast_router %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])
fprintf(f, "mcast_query_use_ifaddr %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));
print_uint(PRINT_ANY,
"mcast_query_use_ifaddr",
"mcast_query_use_ifaddr %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));
if (tb[IFLA_BR_MCAST_QUERIER])
fprintf(f, "mcast_querier %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));
print_uint(PRINT_ANY,
"mcast_querier",
"mcast_querier %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));
if (tb[IFLA_BR_MCAST_HASH_ELASTICITY])
fprintf(f, "mcast_hash_elasticity %u ",
rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));
print_uint(PRINT_ANY,
"mcast_hash_elasticity",
"mcast_hash_elasticity %u ",
rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));
if (tb[IFLA_BR_MCAST_HASH_MAX])
fprintf(f, "mcast_hash_max %u ",
rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));
print_uint(PRINT_ANY,
"mcast_hash_max",
"mcast_hash_max %u ",
rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));
if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])
fprintf(f, "mcast_last_member_count %u ",
rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));
print_uint(PRINT_ANY,
"mcast_last_member_cnt",
"mcast_last_member_count %u ",
rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));
if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])
fprintf(f, "mcast_startup_query_count %u ",
rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]));
print_uint(PRINT_ANY,
"mcast_startup_query_cnt",
"mcast_startup_query_count %u ",
rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]));
if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])
fprintf(f, "mcast_last_member_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]));
print_lluint(PRINT_ANY,
"mcast_last_member_intvl",
"mcast_last_member_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]));
if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])
fprintf(f, "mcast_membership_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]));
print_lluint(PRINT_ANY,
"mcast_membership_intvl",
"mcast_membership_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]));
if (tb[IFLA_BR_MCAST_QUERIER_INTVL])
fprintf(f, "mcast_querier_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]));
print_lluint(PRINT_ANY,
"mcast_querier_intvl",
"mcast_querier_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]));
if (tb[IFLA_BR_MCAST_QUERY_INTVL])
fprintf(f, "mcast_query_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]));
print_lluint(PRINT_ANY,
"mcast_query_intvl",
"mcast_query_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]));
if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])
fprintf(f, "mcast_query_response_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]));
print_lluint(PRINT_ANY,
"mcast_query_response_intvl",
"mcast_query_response_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]));
if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])
fprintf(f, "mcast_startup_query_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]));
print_lluint(PRINT_ANY,
"mcast_startup_query_intvl",
"mcast_startup_query_interval %llu ",
rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]));
if (tb[IFLA_BR_MCAST_STATS_ENABLED])
fprintf(f, "mcast_stats_enabled %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_STATS_ENABLED]));
print_uint(PRINT_ANY,
"mcast_stats_enabled",
"mcast_stats_enabled %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_STATS_ENABLED]));
if (tb[IFLA_BR_MCAST_IGMP_VERSION])
fprintf(f, "mcast_igmp_version %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_IGMP_VERSION]));
print_uint(PRINT_ANY,
"mcast_igmp_version",
"mcast_igmp_version %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_IGMP_VERSION]));
if (tb[IFLA_BR_MCAST_MLD_VERSION])
fprintf(f, "mcast_mld_version %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_MLD_VERSION]));
print_uint(PRINT_ANY,
"mcast_mld_version",
"mcast_mld_version %u ",
rta_getattr_u8(tb[IFLA_BR_MCAST_MLD_VERSION]));
if (tb[IFLA_BR_NF_CALL_IPTABLES])
fprintf(f, "nf_call_iptables %u ",
rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES]));
print_uint(PRINT_ANY,
"nf_call_iptables",
"nf_call_iptables %u ",
rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES]));
if (tb[IFLA_BR_NF_CALL_IP6TABLES])
fprintf(f, "nf_call_ip6tables %u ",
rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]));
print_uint(PRINT_ANY,
"nf_call_ip6tables",
"nf_call_ip6tables %u ",
rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]));
if (tb[IFLA_BR_NF_CALL_ARPTABLES])
fprintf(f, "nf_call_arptables %u ",
rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]));
print_uint(PRINT_ANY,
"nf_call_arptables",
"nf_call_arptables %u ",
rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]));
}
static void bridge_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
print_explain(f);
}

View File

@ -56,14 +56,52 @@ static const char *port_states[] = {
static void print_portstate(FILE *f, __u8 state)
{
if (state <= BR_STATE_BLOCKING)
fprintf(f, "state %s ", port_states[state]);
print_string(PRINT_ANY,
"state",
"state %s ",
port_states[state]);
else
fprintf(f, "state (%d) ", state);
print_int(PRINT_ANY, "state_index", "state (%d) ", state);
}
static void print_onoff(FILE *f, char *flag, __u8 val)
static void _print_onoff(FILE *f, char *json_flag, char *flag, __u8 val)
{
fprintf(f, "%s %s ", flag, val ? "on" : "off");
if (is_json_context())
print_bool(PRINT_JSON, flag, NULL, val);
else
fprintf(f, "%s %s ", flag, val ? "on" : "off");
}
static void _print_hex(FILE *f,
const char *json_attr,
const char *attr,
__u16 val)
{
if (is_json_context()) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "0x%x", val);
print_string(PRINT_JSON, json_attr, NULL, b1);
} else {
fprintf(f, "%s 0x%x ", attr, val);
}
}
static void _print_timer(FILE *f, const char *attr, struct rtattr *timer)
{
struct timeval tv;
__jiffies_to_tv(&tv, rta_getattr_u64(timer));
if (is_json_context()) {
json_writer_t *jw = get_json_writer();
jsonw_name(jw, attr);
jsonw_printf(jw, "%i.%.2i",
(int)tv.tv_sec, (int)tv.tv_usec / 10000);
} else {
fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec,
(int)tv.tv_usec / 10000);
}
}
static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
@ -76,59 +114,70 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
print_portstate(f, rta_getattr_u8(tb[IFLA_BRPORT_STATE]));
if (tb[IFLA_BRPORT_PRIORITY])
fprintf(f, "priority %d ",
rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY]));
print_int(PRINT_ANY,
"priority",
"priority %d ",
rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY]));
if (tb[IFLA_BRPORT_COST])
fprintf(f, "cost %d ",
rta_getattr_u32(tb[IFLA_BRPORT_COST]));
print_int(PRINT_ANY,
"cost",
"cost %d ",
rta_getattr_u32(tb[IFLA_BRPORT_COST]));
if (tb[IFLA_BRPORT_MODE])
print_onoff(f, "hairpin",
rta_getattr_u8(tb[IFLA_BRPORT_MODE]));
_print_onoff(f, "mode", "hairpin",
rta_getattr_u8(tb[IFLA_BRPORT_MODE]));
if (tb[IFLA_BRPORT_GUARD])
print_onoff(f, "guard",
rta_getattr_u8(tb[IFLA_BRPORT_GUARD]));
_print_onoff(f, "guard", "guard",
rta_getattr_u8(tb[IFLA_BRPORT_GUARD]));
if (tb[IFLA_BRPORT_PROTECT])
print_onoff(f, "root_block",
rta_getattr_u8(tb[IFLA_BRPORT_PROTECT]));
_print_onoff(f, "protect", "root_block",
rta_getattr_u8(tb[IFLA_BRPORT_PROTECT]));
if (tb[IFLA_BRPORT_FAST_LEAVE])
print_onoff(f, "fastleave",
rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
_print_onoff(f, "fast_leave", "fastleave",
rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
if (tb[IFLA_BRPORT_LEARNING])
print_onoff(f, "learning",
rta_getattr_u8(tb[IFLA_BRPORT_LEARNING]));
_print_onoff(f, "learning", "learning",
rta_getattr_u8(tb[IFLA_BRPORT_LEARNING]));
if (tb[IFLA_BRPORT_UNICAST_FLOOD])
print_onoff(f, "flood",
rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
_print_onoff(f, "unicast_flood", "flood",
rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
if (tb[IFLA_BRPORT_ID])
fprintf(f, "port_id 0x%x ",
rta_getattr_u16(tb[IFLA_BRPORT_ID]));
_print_hex(f, "id", "port_id",
rta_getattr_u16(tb[IFLA_BRPORT_ID]));
if (tb[IFLA_BRPORT_NO])
fprintf(f, "port_no 0x%x ",
rta_getattr_u16(tb[IFLA_BRPORT_NO]));
_print_hex(f, "no", "port_no",
rta_getattr_u16(tb[IFLA_BRPORT_NO]));
if (tb[IFLA_BRPORT_DESIGNATED_PORT])
fprintf(f, "designated_port %u ",
rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_PORT]));
print_uint(PRINT_ANY,
"designated_port",
"designated_port %u ",
rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_PORT]));
if (tb[IFLA_BRPORT_DESIGNATED_COST])
fprintf(f, "designated_cost %u ",
rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_COST]));
print_uint(PRINT_ANY,
"designated_cost",
"designated_cost %u ",
rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_COST]));
if (tb[IFLA_BRPORT_BRIDGE_ID]) {
char bridge_id[32];
br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_BRIDGE_ID]),
bridge_id, sizeof(bridge_id));
fprintf(f, "designated_bridge %s ", bridge_id);
print_string(PRINT_ANY,
"bridge_id",
"designated_bridge %s ",
bridge_id);
}
if (tb[IFLA_BRPORT_ROOT_ID]) {
@ -136,65 +185,59 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_ROOT_ID]),
root_id, sizeof(root_id));
fprintf(f, "designated_root %s ", root_id);
print_string(PRINT_ANY,
"root_id",
"designated_root %s ", root_id);
}
if (tb[IFLA_BRPORT_HOLD_TIMER]) {
struct timeval tv;
__u64 htimer;
if (tb[IFLA_BRPORT_HOLD_TIMER])
_print_timer(f, "hold_timer", tb[IFLA_BRPORT_HOLD_TIMER]);
htimer = rta_getattr_u64(tb[IFLA_BRPORT_HOLD_TIMER]);
__jiffies_to_tv(&tv, htimer);
fprintf(f, "hold_timer %4i.%.2i ", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
}
if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER])
_print_timer(f, "message_age_timer",
tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]);
if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]) {
struct timeval tv;
__u64 agetimer;
agetimer = rta_getattr_u64(tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]);
__jiffies_to_tv(&tv, agetimer);
fprintf(f, "message_age_timer %4i.%.2i ", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
}
if (tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]) {
struct timeval tv;
__u64 fwdtimer;
fwdtimer = rta_getattr_u64(tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]);
__jiffies_to_tv(&tv, fwdtimer);
fprintf(f, "forward_delay_timer %4i.%.2i ", (int)tv.tv_sec,
(int)tv.tv_usec/10000);
}
if (tb[IFLA_BRPORT_FORWARD_DELAY_TIMER])
_print_timer(f, "forward_delay_timer",
tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]);
if (tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK])
fprintf(f, "topology_change_ack %u ",
rta_getattr_u8(tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK]));
print_uint(PRINT_ANY,
"topology_change_ack",
"topology_change_ack %u ",
rta_getattr_u8(tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK]));
if (tb[IFLA_BRPORT_CONFIG_PENDING])
fprintf(f, "config_pending %u ",
rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING]));
print_uint(PRINT_ANY,
"config_pending",
"config_pending %u ",
rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING]));
if (tb[IFLA_BRPORT_PROXYARP])
print_onoff(f, "proxy_arp",
rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP]));
_print_onoff(f, "proxyarp", "proxy_arp",
rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP]));
if (tb[IFLA_BRPORT_PROXYARP_WIFI])
print_onoff(f, "proxy_arp_wifi",
rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI]));
_print_onoff(f, "proxyarp_wifi", "proxy_arp_wifi",
rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI]));
if (tb[IFLA_BRPORT_MULTICAST_ROUTER])
fprintf(f, "mcast_router %u ",
rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER]));
print_uint(PRINT_ANY,
"multicast_router",
"mcast_router %u ",
rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER]));
if (tb[IFLA_BRPORT_FAST_LEAVE])
print_onoff(f, "mcast_fast_leave",
rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
// not printing any json here because
// we already printed fast_leave before
print_string(PRINT_FP,
NULL,
"mcast_fast_leave %s ",
rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]) ? "on" : "off");
if (tb[IFLA_BRPORT_MCAST_FLOOD])
print_onoff(f, "mcast_flood",
rta_getattr_u8(tb[IFLA_BRPORT_MCAST_FLOOD]));
_print_onoff(f, "mcast_flood", "mcast_flood",
rta_getattr_u8(tb[IFLA_BRPORT_MCAST_FLOOD]));
}
static void bridge_slave_parse_on_off(char *arg_name, char *arg_val,

View File

@ -89,11 +89,11 @@ static void set_ctrlmode(char *name, char *arg,
static void print_ctrlmode(FILE *f, __u32 cm)
{
fprintf(f, "<");
#define _PF(cmflag, cmname) \
if (cm & cmflag) { \
cm &= ~cmflag; \
fprintf(f, "%s%s", cmname, cm ? "," : ""); \
open_json_array(PRINT_ANY, is_json_context() ? "ctrlmode" : "<");
#define _PF(cmflag, cmname) \
if (cm & cmflag) { \
cm &= ~cmflag; \
print_string(PRINT_ANY, NULL, cm ? "%s," : "%s", cmname); \
}
_PF(CAN_CTRLMODE_LOOPBACK, "LOOPBACK");
_PF(CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY");
@ -105,8 +105,8 @@ static void print_ctrlmode(FILE *f, __u32 cm)
_PF(CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK");
#undef _PF
if (cm)
fprintf(f, "%x", cm);
fprintf(f, "> ");
print_hex(PRINT_ANY, NULL, "%x", cm);
close_json_array(PRINT_ANY, "> ");
}
static int can_parse_opt(struct link_util *lu, int argc, char **argv,
@ -260,6 +260,14 @@ static const char *can_state_names[CAN_STATE_MAX] = {
[CAN_STATE_SLEEPING] = "SLEEPING"
};
static void can_print_json_timing_min_max(const char *attr, int min, int max)
{
open_json_object(attr);
print_int(PRINT_JSON, "min", NULL, min);
print_int(PRINT_JSON, "max", NULL, max);
close_json_object();
}
static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
if (!tb)
@ -283,24 +291,53 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
struct can_berr_counter *bc =
RTA_DATA(tb[IFLA_CAN_BERR_COUNTER]);
fprintf(f, "(berr-counter tx %d rx %d) ", bc->txerr, bc->rxerr);
if (is_json_context()) {
open_json_object("berr_counter");
print_int(PRINT_JSON, "tx", NULL, bc->txerr);
print_int(PRINT_JSON, "rx", NULL, bc->rxerr);
close_json_object();
} else {
fprintf(f, "(berr-counter tx %d rx %d) ",
bc->txerr, bc->rxerr);
}
}
if (tb[IFLA_CAN_RESTART_MS]) {
__u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]);
fprintf(f, "restart-ms %d ", *restart_ms);
print_int(PRINT_ANY,
"restart_ms",
"restart-ms %d ",
*restart_ms);
}
/* bittiming is irrelevant if fixed bitrate is defined */
if (tb[IFLA_CAN_BITTIMING] && !tb[IFLA_CAN_BITRATE_CONST]) {
struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]);
fprintf(f, "\n bitrate %d sample-point %.3f ",
bt->bitrate, (float)bt->sample_point / 1000.);
fprintf(f, "\n tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d",
bt->tq, bt->prop_seg, bt->phase_seg1, bt->phase_seg2,
bt->sjw);
if (is_json_context()) {
open_json_object("bittiming");
print_int(PRINT_ANY, "bitrate", NULL, bt->bitrate);
jsonw_float_field_fmt(get_json_writer(),
"sample_point", "%.3f",
(float) bt->sample_point / 1000.);
print_int(PRINT_ANY, "tq", NULL, bt->tq);
print_int(PRINT_ANY, "prop_seg", NULL, bt->prop_seg);
print_int(PRINT_ANY, "phase_seg1",
NULL, bt->phase_seg1);
print_int(PRINT_ANY, "phase_seg2",
NULL, bt->phase_seg2);
print_int(PRINT_ANY, "sjw", NULL, bt->sjw);
close_json_object();
} else {
fprintf(f, "\n bitrate %d sample-point %.3f ",
bt->bitrate, (float) bt->sample_point / 1000.);
fprintf(f,
"\n tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d",
bt->tq, bt->prop_seg,
bt->phase_seg1, bt->phase_seg2,
bt->sjw);
}
}
/* bittiming const is irrelevant if fixed bitrate is defined */
@ -308,40 +345,68 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
struct can_bittiming_const *btc =
RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]);
fprintf(f, "\n %s: tseg1 %d..%d tseg2 %d..%d "
"sjw 1..%d brp %d..%d brp-inc %d",
btc->name, btc->tseg1_min, btc->tseg1_max,
btc->tseg2_min, btc->tseg2_max, btc->sjw_max,
btc->brp_min, btc->brp_max, btc->brp_inc);
if (is_json_context()) {
open_json_object("bittiming_const");
print_string(PRINT_JSON, "name", NULL, btc->name);
can_print_json_timing_min_max("tseg1",
btc->tseg1_min,
btc->tseg1_max);
can_print_json_timing_min_max("tseg2",
btc->tseg2_min,
btc->tseg2_max);
can_print_json_timing_min_max("sjw", 1, btc->sjw_max);
can_print_json_timing_min_max("brp",
btc->brp_min,
btc->brp_max);
print_int(PRINT_JSON, "brp_inc", NULL, btc->brp_inc);
close_json_object();
} else {
fprintf(f, "\n %s: tseg1 %d..%d tseg2 %d..%d "
"sjw 1..%d brp %d..%d brp-inc %d",
btc->name, btc->tseg1_min, btc->tseg1_max,
btc->tseg2_min, btc->tseg2_max, btc->sjw_max,
btc->brp_min, btc->brp_max, btc->brp_inc);
}
}
if (tb[IFLA_CAN_BITRATE_CONST]) {
__u32 *bitrate_const = RTA_DATA(tb[IFLA_CAN_BITRATE_CONST]);
int bitrate_cnt = RTA_PAYLOAD(tb[IFLA_CAN_BITRATE_CONST]) /
sizeof(*bitrate_const);
sizeof(*bitrate_const);
int i;
__u32 bitrate = 0;
if (tb[IFLA_CAN_BITTIMING]) {
struct can_bittiming *bt =
RTA_DATA(tb[IFLA_CAN_BITTIMING]);
RTA_DATA(tb[IFLA_CAN_BITTIMING]);
bitrate = bt->bitrate;
}
fprintf(f, "\n bitrate %u", bitrate);
fprintf(f, "\n [");
if (is_json_context()) {
print_uint(PRINT_JSON,
"bittiming_bitrate",
NULL, bitrate);
open_json_array(PRINT_JSON, "bitrate_const");
for (i = 0; i < bitrate_cnt; ++i)
print_uint(PRINT_JSON, NULL, NULL,
bitrate_const[i]);
close_json_array(PRINT_JSON, NULL);
} else {
fprintf(f, "\n bitrate %u", bitrate);
fprintf(f, "\n [");
for (i = 0; i < bitrate_cnt - 1; ++i) {
/* This will keep lines below 80 signs */
if (!(i % 6) && i)
fprintf(f, "\n ");
fprintf(f, "%8u, ", bitrate_const[i]);
}
for (i = 0; i < bitrate_cnt - 1; ++i) {
/* This will keep lines below 80 signs */
if (!(i % 6) && i)
fprintf(f, "\n ");
fprintf(f, "%8u, ", bitrate_const[i]);
fprintf(f, "%8u ]", bitrate_const[i]);
}
if (!(i % 6) && i)
fprintf(f, "\n ");
fprintf(f, "%8u ]", bitrate_const[i]);
}
/* data bittiming is irrelevant if fixed bitrate is defined */
@ -349,12 +414,30 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
struct can_bittiming *dbt =
RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]);
fprintf(f, "\n dbitrate %d dsample-point %.3f ",
dbt->bitrate, (float)dbt->sample_point / 1000.);
fprintf(f, "\n dtq %d dprop-seg %d dphase-seg1 %d "
"dphase-seg2 %d dsjw %d",
dbt->tq, dbt->prop_seg, dbt->phase_seg1,
dbt->phase_seg2, dbt->sjw);
if (is_json_context()) {
open_json_object("data_bittiming");
print_int(PRINT_JSON, "bitrate", NULL, dbt->bitrate);
jsonw_float_field_fmt(get_json_writer(),
"sample_point",
"%.3f",
(float) dbt->sample_point / 1000.);
print_int(PRINT_JSON, "tq", NULL, dbt->tq);
print_int(PRINT_JSON, "prop_seg", NULL, dbt->prop_seg);
print_int(PRINT_JSON, "phase_seg1",
NULL, dbt->phase_seg1);
print_int(PRINT_JSON, "phase_seg2",
NULL, dbt->phase_seg2);
print_int(PRINT_JSON, "sjw", NULL, dbt->sjw);
close_json_object();
} else {
fprintf(f, "\n dbitrate %d dsample-point %.3f ",
dbt->bitrate,
(float) dbt->sample_point / 1000.);
fprintf(f, "\n dtq %d dprop-seg %d dphase-seg1 %d "
"dphase-seg2 %d dsjw %d",
dbt->tq, dbt->prop_seg, dbt->phase_seg1,
dbt->phase_seg2, dbt->sjw);
}
}
/* data bittiming const is irrelevant if fixed bitrate is defined */
@ -363,63 +446,102 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
struct can_bittiming_const *dbtc =
RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING_CONST]);
fprintf(f, "\n %s: dtseg1 %d..%d dtseg2 %d..%d "
"dsjw 1..%d dbrp %d..%d dbrp-inc %d",
dbtc->name, dbtc->tseg1_min, dbtc->tseg1_max,
dbtc->tseg2_min, dbtc->tseg2_max, dbtc->sjw_max,
dbtc->brp_min, dbtc->brp_max, dbtc->brp_inc);
if (is_json_context()) {
open_json_object("data_bittiming_const");
print_string(PRINT_JSON, "name", NULL, dbtc->name);
can_print_json_timing_min_max("tseg1",
dbtc->tseg1_min,
dbtc->tseg1_max);
can_print_json_timing_min_max("tseg2",
dbtc->tseg2_min,
dbtc->tseg2_max);
can_print_json_timing_min_max("sjw", 1, dbtc->sjw_max);
can_print_json_timing_min_max("brp",
dbtc->brp_min,
dbtc->brp_max);
print_int(PRINT_JSON, "brp_inc", NULL, dbtc->brp_inc);
close_json_object();
} else {
fprintf(f, "\n %s: dtseg1 %d..%d dtseg2 %d..%d "
"dsjw 1..%d dbrp %d..%d dbrp-inc %d",
dbtc->name, dbtc->tseg1_min, dbtc->tseg1_max,
dbtc->tseg2_min, dbtc->tseg2_max, dbtc->sjw_max,
dbtc->brp_min, dbtc->brp_max, dbtc->brp_inc);
}
}
if (tb[IFLA_CAN_DATA_BITRATE_CONST]) {
__u32 *dbitrate_const =
RTA_DATA(tb[IFLA_CAN_DATA_BITRATE_CONST]);
RTA_DATA(tb[IFLA_CAN_DATA_BITRATE_CONST]);
int dbitrate_cnt =
RTA_PAYLOAD(tb[IFLA_CAN_DATA_BITRATE_CONST]) /
sizeof(*dbitrate_const);
RTA_PAYLOAD(tb[IFLA_CAN_DATA_BITRATE_CONST]) /
sizeof(*dbitrate_const);
int i;
__u32 dbitrate = 0;
if (tb[IFLA_CAN_DATA_BITTIMING]) {
struct can_bittiming *dbt =
RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]);
RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]);
dbitrate = dbt->bitrate;
}
fprintf(f, "\n dbitrate %u", dbitrate);
fprintf(f, "\n [");
if (is_json_context()) {
print_uint(PRINT_JSON, "data_bittiming_bitrate",
NULL, dbitrate);
open_json_array(PRINT_JSON, "data_bitrate_const");
for (i = 0; i < dbitrate_cnt; ++i)
print_uint(PRINT_JSON, NULL, NULL,
dbitrate_const[i]);
close_json_array(PRINT_JSON, NULL);
} else {
fprintf(f, "\n dbitrate %u", dbitrate);
fprintf(f, "\n [");
for (i = 0; i < dbitrate_cnt - 1; ++i) {
/* This will keep lines below 80 signs */
if (!(i % 6) && i)
fprintf(f, "\n ");
fprintf(f, "%8u, ", dbitrate_const[i]);
}
for (i = 0; i < dbitrate_cnt - 1; ++i) {
/* This will keep lines below 80 signs */
if (!(i % 6) && i)
fprintf(f, "\n ");
fprintf(f, "%8u, ", dbitrate_const[i]);
fprintf(f, "%8u ]", dbitrate_const[i]);
}
if (!(i % 6) && i)
fprintf(f, "\n ");
fprintf(f, "%8u ]", dbitrate_const[i]);
}
if (tb[IFLA_CAN_TERMINATION_CONST] && tb[IFLA_CAN_TERMINATION]) {
__u16 *trm = RTA_DATA(tb[IFLA_CAN_TERMINATION]);
__u16 *trm_const = RTA_DATA(tb[IFLA_CAN_TERMINATION_CONST]);
int trm_cnt = RTA_PAYLOAD(tb[IFLA_CAN_TERMINATION_CONST]) /
sizeof(*trm_const);
sizeof(*trm_const);
int i;
fprintf(f, "\n termination %hu [ ", *trm);
if (is_json_context()) {
print_hu(PRINT_JSON, "termination", NULL, *trm);
open_json_array(PRINT_JSON, "termination_const");
for (i = 0; i < trm_cnt; ++i)
print_hu(PRINT_JSON, NULL, NULL, trm_const[i]);
close_json_array(PRINT_JSON, NULL);
} else {
fprintf(f, "\n termination %hu [ ", *trm);
for (i = 0; i < trm_cnt - 1; ++i)
fprintf(f, "%hu, ", trm_const[i]);
for (i = 0; i < trm_cnt - 1; ++i)
fprintf(f, "%hu, ", trm_const[i]);
fprintf(f, "%hu ]", trm_const[i]);
fprintf(f, "%hu ]", trm_const[i]);
}
}
if (tb[IFLA_CAN_CLOCK]) {
struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]);
fprintf(f, "\n clock %d", clock->freq);
print_int(PRINT_ANY,
"clock",
"\n clock %d",
clock->freq);
}
}
@ -431,17 +553,32 @@ static void can_print_xstats(struct link_util *lu,
if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) {
stats = RTA_DATA(xstats);
fprintf(f, "\n re-started bus-errors arbit-lost "
"error-warn error-pass bus-off");
fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d",
stats->restarts, stats->bus_error,
stats->arbitration_lost, stats->error_warning,
stats->error_passive, stats->bus_off);
if (is_json_context()) {
print_int(PRINT_JSON, "restarts",
NULL, stats->restarts);
print_int(PRINT_JSON, "bus_error",
NULL, stats->bus_error);
print_int(PRINT_JSON, "arbitration_lost",
NULL, stats->arbitration_lost);
print_int(PRINT_JSON, "error_warning",
NULL, stats->error_warning);
print_int(PRINT_JSON, "error_passive",
NULL, stats->error_passive);
print_int(PRINT_JSON, "bus_off", NULL, stats->bus_off);
} else {
fprintf(f, "\n re-started bus-errors arbit-lost "
"error-warn error-pass bus-off");
fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d",
stats->restarts, stats->bus_error,
stats->arbitration_lost, stats->error_warning,
stats->error_passive, stats->bus_off);
}
}
}
static void can_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
print_usage(f);
}

View File

@ -237,22 +237,28 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
return;
vni = rta_getattr_u32(tb[IFLA_GENEVE_ID]);
fprintf(f, "id %u ", vni);
print_uint(PRINT_ANY, "id", "id %u ", vni);
if (tb[IFLA_GENEVE_REMOTE]) {
__be32 addr = rta_getattr_u32(tb[IFLA_GENEVE_REMOTE]);
if (addr)
fprintf(f, "remote %s ",
format_host(AF_INET, 4, &addr));
print_string(PRINT_ANY,
"remote",
"remote %s ",
format_host(AF_INET, 4, &addr));
} else if (tb[IFLA_GENEVE_REMOTE6]) {
struct in6_addr addr;
memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr));
if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) {
if (!IN6_IS_ADDR_MULTICAST(&addr))
fprintf(f, "remote %s ",
format_host(AF_INET6, sizeof(struct in6_addr), &addr));
print_string(PRINT_ANY,
"remote6",
"remote %s ",
format_host(AF_INET6,
sizeof(struct in6_addr),
&addr));
}
}
@ -260,47 +266,81 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
__u8 ttl = rta_getattr_u8(tb[IFLA_GENEVE_TTL]);
if (ttl)
fprintf(f, "ttl %d ", ttl);
print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
}
if (tb[IFLA_GENEVE_TOS] &&
(tos = rta_getattr_u8(tb[IFLA_GENEVE_TOS]))) {
if (tos == 1)
fprintf(f, "tos inherit ");
else
fprintf(f, "tos %#x ", tos);
if (is_json_context()) {
print_0xhex(PRINT_JSON, "tos", "%#x", tos);
} else {
if (tos == 1) {
print_string(PRINT_FP,
"tos",
"tos %s ",
"inherit");
} else {
fprintf(f, "tos %#x ", tos);
}
}
}
if (tb[IFLA_GENEVE_LABEL]) {
__u32 label = rta_getattr_u32(tb[IFLA_GENEVE_LABEL]);
if (label)
fprintf(f, "flowlabel %#x ", ntohl(label));
print_0xhex(PRINT_ANY,
"label",
"flowlabel %#x ",
ntohl(label));
}
if (tb[IFLA_GENEVE_PORT])
fprintf(f, "dstport %u ",
rta_getattr_be16(tb[IFLA_GENEVE_PORT]));
print_uint(PRINT_ANY,
"port",
"dstport %u ",
rta_getattr_be16(tb[IFLA_GENEVE_PORT]));
if (tb[IFLA_GENEVE_COLLECT_METADATA])
fputs("external ", f);
print_bool(PRINT_ANY, "collect_metadata", "external ", true);
if (tb[IFLA_GENEVE_UDP_CSUM]) {
if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_CSUM]))
fputs("no", f);
fputs("udpcsum ", f);
if (is_json_context()) {
print_bool(PRINT_JSON,
"udp_csum",
NULL,
rta_getattr_u8(tb[IFLA_GENEVE_UDP_CSUM]));
} else {
if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_CSUM]))
fputs("no", f);
fputs("udpcsum ", f);
}
}
if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
fputs("no", f);
fputs("udp6zerocsumtx ", f);
if (is_json_context()) {
print_bool(PRINT_JSON,
"udp_zero_csum6_tx",
NULL,
rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]));
} else {
if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
fputs("no", f);
fputs("udp6zerocsumtx ", f);
}
}
if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
fputs("no", f);
fputs("udp6zerocsumrx ", f);
if (is_json_context()) {
print_bool(PRINT_JSON,
"udp_zero_csum6_rx",
NULL,
rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]));
} else {
if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
fputs("no", f);
fputs("udp6zerocsumrx ", f);
}
}
}

View File

@ -110,30 +110,36 @@ static void hsr_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]) < ETH_ALEN)
return;
fprintf(f, "slave1 ");
if (tb[IFLA_HSR_SLAVE1])
fprintf(f, "%s ",
ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE1])));
print_string(PRINT_ANY,
"slave1",
"slave1 %s ",
ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE1])));
else
fprintf(f, "<none> ");
print_null(PRINT_ANY, "slave1", "slave1 %s ", "<none>");
fprintf(f, "slave2 ");
if (tb[IFLA_HSR_SLAVE2])
fprintf(f, "%s ",
ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE2])));
print_string(PRINT_ANY,
"slave2",
"slave2 %s ",
ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE2])));
else
fprintf(f, "<none> ");
print_null(PRINT_ANY, "slave2", "slave2 %s ", "<none>");
if (tb[IFLA_HSR_SEQ_NR])
fprintf(f, "sequence %d ",
rta_getattr_u16(tb[IFLA_HSR_SEQ_NR]));
print_int(PRINT_ANY,
"seq_nr",
"sequence %d ",
rta_getattr_u16(tb[IFLA_HSR_SEQ_NR]));
if (tb[IFLA_HSR_SUPERVISION_ADDR])
fprintf(f, "supervision %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_HSR_SUPERVISION_ADDR]),
RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]),
ARPHRD_VOID,
b1, sizeof(b1)));
print_string(PRINT_ANY,
"supervision_addr",
"supervision %s ",
ll_addr_n2a(RTA_DATA(tb[IFLA_HSR_SUPERVISION_ADDR]),
RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]),
ARPHRD_VOID,
b1, sizeof(b1)));
}
static void hsr_print_help(struct link_util *lu, int argc, char **argv,

View File

@ -91,23 +91,43 @@ static void ipoib_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
RTA_PAYLOAD(tb[IFLA_IPOIB_PKEY]) < sizeof(__u16))
return;
fprintf(f, "pkey %#.4x ", rta_getattr_u16(tb[IFLA_IPOIB_PKEY]));
__u16 pkey = rta_getattr_u16(tb[IFLA_IPOIB_PKEY]);
if (is_json_context()) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "%#.4x", pkey);
print_string(PRINT_JSON, "key", NULL, b1);
} else {
fprintf(f, "pkey %#.4x ", pkey);
}
if (!tb[IFLA_IPOIB_MODE] ||
RTA_PAYLOAD(tb[IFLA_IPOIB_MODE]) < sizeof(__u16))
return;
mode = rta_getattr_u16(tb[IFLA_IPOIB_MODE]);
fprintf(f, "mode %s ",
const char *mode_str =
mode == IPOIB_MODE_DATAGRAM ? "datagram" :
mode == IPOIB_MODE_CONNECTED ? "connected" :
"unknown");
mode == IPOIB_MODE_CONNECTED ? "connected" : "unknown";
print_string(PRINT_ANY, "mode", "mode %s ", mode_str);
if (!tb[IFLA_IPOIB_UMCAST] ||
RTA_PAYLOAD(tb[IFLA_IPOIB_UMCAST]) < sizeof(__u16))
return;
fprintf(f, "umcast %.4x ", rta_getattr_u16(tb[IFLA_IPOIB_UMCAST]));
__u16 umcast = rta_getattr_u16(tb[IFLA_IPOIB_UMCAST]);
if (is_json_context()) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "%.4x", umcast);
print_string(PRINT_JSON, "umcast", NULL, b1);
} else {
fprintf(f, "umcast %.4x ", umcast);
}
}
static void ipoib_print_help(struct link_util *lu, int argc, char **argv,

View File

@ -68,11 +68,11 @@ static void ipvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if (tb[IFLA_IPVLAN_MODE]) {
if (RTA_PAYLOAD(tb[IFLA_IPVLAN_MODE]) == sizeof(__u16)) {
__u16 mode = rta_getattr_u16(tb[IFLA_IPVLAN_MODE]);
fprintf(f, " mode %s ",
mode == IPVLAN_MODE_L2 ? "l2" :
const char *mode_str = mode == IPVLAN_MODE_L2 ? "l2" :
mode == IPVLAN_MODE_L3 ? "l3" :
mode == IPVLAN_MODE_L3S ? "l3s" : "unknown");
mode == IPVLAN_MODE_L3S ? "l3s" : "unknown";
print_string(PRINT_ANY, "mode", " mode %s ", mode_str);
}
}
}

View File

@ -193,13 +193,15 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
return;
mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
fprintf(f, "mode %s ",
mode == MACVLAN_MODE_PRIVATE ? "private"
: mode == MACVLAN_MODE_VEPA ? "vepa"
: mode == MACVLAN_MODE_BRIDGE ? "bridge"
: mode == MACVLAN_MODE_PASSTHRU ? "passthru"
: mode == MACVLAN_MODE_SOURCE ? "source"
: "unknown");
print_string(PRINT_ANY,
"mode",
"mode %s ",
mode == MACVLAN_MODE_PRIVATE ? "private"
: mode == MACVLAN_MODE_VEPA ? "vepa"
: mode == MACVLAN_MODE_BRIDGE ? "bridge"
: mode == MACVLAN_MODE_PASSTHRU ? "passthru"
: mode == MACVLAN_MODE_SOURCE ? "source"
: "unknown");
if (!tb[IFLA_MACVLAN_FLAGS] ||
RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
@ -208,7 +210,7 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
if (flags & MACVLAN_FLAG_NOPROMISC)
fprintf(f, "nopromisc ");
print_bool(PRINT_ANY, "nopromisc", "nopromisc ", true);
/* in source mode, there are more options to print */
@ -220,7 +222,7 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
return;
count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
fprintf(f, "remotes (%d) ", count);
print_int(PRINT_ANY, "macaddr_count", "remotes (%d) ", count);
if (!tb[IFLA_MACVLAN_MACADDR_DATA])
return;
@ -228,18 +230,29 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]);
len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]);
open_json_array(PRINT_JSON, "macaddr_data");
for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
if (rta->rta_type != IFLA_MACVLAN_MACADDR ||
RTA_PAYLOAD(rta) < 6)
continue;
addr = RTA_DATA(rta);
fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0],
addr[1], addr[2], addr[3], addr[4], addr[5]);
if (is_json_context()) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1),
"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr[0],
addr[1], addr[2], addr[3], addr[4], addr[5]);
print_string(PRINT_JSON, NULL, NULL, b1);
} else {
fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0],
addr[1], addr[2], addr[3], addr[4], addr[5]);
}
}
close_json_array(PRINT_JSON, NULL);
}
static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
print_explain(lu, f);
}

View File

@ -164,37 +164,51 @@ static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
return 0;
}
static void vlan_print_map(FILE *f, char *name, struct rtattr *attr)
static void vlan_print_map(FILE *f,
const char *name_json,
const char *name_fp,
struct rtattr *attr)
{
struct ifla_vlan_qos_mapping *m;
struct rtattr *i;
int rem;
fprintf(f, "\n %s { ", name);
open_json_array(PRINT_JSON, name_json);
print_string(PRINT_FP, NULL, "\n %s { ", name_fp);
rem = RTA_PAYLOAD(attr);
for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
m = RTA_DATA(i);
fprintf(f, "%u:%u ", m->from, m->to);
if (is_json_context()) {
open_json_object(NULL);
print_uint(PRINT_JSON, "from", NULL, m->from);
print_uint(PRINT_JSON, "to", NULL, m->to);
close_json_object();
} else {
fprintf(f, "%u:%u ", m->from, m->to);
}
}
fprintf(f, "} ");
close_json_array(PRINT_JSON, NULL);
print_string(PRINT_FP, NULL, "%s ", "}");
}
static void vlan_print_flags(FILE *fp, __u32 flags)
{
fprintf(fp, "<");
#define _PF(f) if (flags & VLAN_FLAG_##f) { \
flags &= ~VLAN_FLAG_##f; \
fprintf(fp, #f "%s", flags ? "," : ""); \
}
open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
#define _PF(f) if (flags & VLAN_FLAG_##f) { \
flags &= ~VLAN_FLAG_##f; \
print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); \
}
_PF(REORDER_HDR);
_PF(GVRP);
_PF(MVRP);
_PF(LOOSE_BINDING);
#undef _PF
if (flags)
fprintf(fp, "%x", flags);
fprintf(fp, "> ");
print_hex(PRINT_ANY, NULL, "%x", flags);
close_json_array(PRINT_ANY, "> ");
}
static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
@ -214,13 +228,19 @@ static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
return;
if (tb[IFLA_VLAN_PROTOCOL])
fprintf(f, "protocol %s ",
ll_proto_n2a(rta_getattr_u16(tb[IFLA_VLAN_PROTOCOL]),
print_string(PRINT_ANY,
"protocol",
"protocol %s ",
ll_proto_n2a(
rta_getattr_u16(tb[IFLA_VLAN_PROTOCOL]),
b1, sizeof(b1)));
else
fprintf(f, "protocol 802.1q ");
print_string(PRINT_ANY, "protocol", "protocol %s ", "802.1q");
fprintf(f, "id %u ", rta_getattr_u16(tb[IFLA_VLAN_ID]));
print_uint(PRINT_ANY,
"id",
"id %u ",
rta_getattr_u16(tb[IFLA_VLAN_ID]));
if (tb[IFLA_VLAN_FLAGS]) {
if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
@ -229,13 +249,19 @@ static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
vlan_print_flags(f, flags->flags);
}
if (tb[IFLA_VLAN_INGRESS_QOS])
vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
vlan_print_map(f,
"ingress_qos",
"ingress-qos-map",
tb[IFLA_VLAN_INGRESS_QOS]);
if (tb[IFLA_VLAN_EGRESS_QOS])
vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
vlan_print_map(f,
"egress_qos",
"egress-qos-map",
tb[IFLA_VLAN_EGRESS_QOS]);
}
static void vlan_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
print_explain(f);
}

View File

@ -62,7 +62,10 @@ static void vrf_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
return;
if (tb[IFLA_VRF_TABLE])
fprintf(f, "table %u ", rta_getattr_u32(tb[IFLA_VRF_TABLE]));
print_uint(PRINT_ANY,
"table",
"table %u ",
rta_getattr_u32(tb[IFLA_VRF_TABLE]));
}
static void vrf_slave_print_opt(struct link_util *lu, FILE *f,
@ -72,13 +75,15 @@ static void vrf_slave_print_opt(struct link_util *lu, FILE *f,
return;
if (tb[IFLA_VRF_PORT_TABLE]) {
fprintf(f, "table %u ",
rta_getattr_u32(tb[IFLA_VRF_PORT_TABLE]));
print_uint(PRINT_ANY,
"table",
"table %u ",
rta_getattr_u32(tb[IFLA_VRF_PORT_TABLE]));
}
}
static void vrf_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
vrf_explain(f);
}

View File

@ -406,18 +406,22 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
return;
vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]);
fprintf(f, "id %u ", vni);
print_uint(PRINT_ANY, "id", "id %u ", vni);
if (tb[IFLA_VXLAN_GROUP]) {
__be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
if (addr) {
if (IN_MULTICAST(ntohl(addr)))
fprintf(f, "group %s ",
format_host(AF_INET, 4, &addr));
print_string(PRINT_ANY,
"group",
"group %s ",
format_host(AF_INET, 4, &addr));
else
fprintf(f, "remote %s ",
format_host(AF_INET, 4, &addr));
print_string(PRINT_ANY,
"remote",
"remote %s ",
format_host(AF_INET, 4, &addr));
}
} else if (tb[IFLA_VXLAN_GROUP6]) {
struct in6_addr addr;
@ -425,11 +429,19 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_GROUP6]), sizeof(struct in6_addr));
if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) {
if (IN6_IS_ADDR_MULTICAST(&addr))
fprintf(f, "group %s ",
format_host(AF_INET6, sizeof(struct in6_addr), &addr));
print_string(PRINT_ANY,
"group6",
"group %s ",
format_host(AF_INET6,
sizeof(struct in6_addr),
&addr));
else
fprintf(f, "remote %s ",
format_host(AF_INET6, sizeof(struct in6_addr), &addr));
print_string(PRINT_ANY,
"remote6",
"remote %s ",
format_host(AF_INET6,
sizeof(struct in6_addr),
&addr));
}
}
@ -437,15 +449,21 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
__be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]);
if (addr)
fprintf(f, "local %s ",
format_host(AF_INET, 4, &addr));
print_string(PRINT_ANY,
"local",
"local %s ",
format_host(AF_INET, 4, &addr));
} else if (tb[IFLA_VXLAN_LOCAL6]) {
struct in6_addr addr;
memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr));
if (!IN6_IS_ADDR_UNSPECIFIED(&addr))
fprintf(f, "local %s ",
format_host(AF_INET6, sizeof(struct in6_addr), &addr));
print_string(PRINT_ANY,
"local6",
"local %s ",
format_host(AF_INET6,
sizeof(struct in6_addr),
&addr));
}
if (tb[IFLA_VXLAN_LINK] &&
@ -453,110 +471,155 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
const char *n = if_indextoname(link, s2);
if (n)
fprintf(f, "dev %s ", n);
print_string(PRINT_ANY, "link", "dev %s ", n);
else
fprintf(f, "dev %u ", link);
print_uint(PRINT_ANY, "link_index", "dev %u ", link);
}
if (tb[IFLA_VXLAN_PORT_RANGE]) {
const struct ifla_vxlan_port_range *r
= RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
fprintf(f, "srcport %u %u ", ntohs(r->low), ntohs(r->high));
if (is_json_context()) {
open_json_object("port_range");
print_uint(PRINT_JSON, "low", NULL, ntohs(r->low));
print_uint(PRINT_JSON, "high", NULL, ntohs(r->high));
close_json_object();
} else {
fprintf(f, "srcport %u %u ",
ntohs(r->low), ntohs(r->high));
}
}
if (tb[IFLA_VXLAN_PORT])
fprintf(f, "dstport %u ",
rta_getattr_be16(tb[IFLA_VXLAN_PORT]));
print_uint(PRINT_ANY,
"port",
"dstport %u ",
rta_getattr_be16(tb[IFLA_VXLAN_PORT]));
if (tb[IFLA_VXLAN_LEARNING] &&
!rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
fputs("nolearning ", f);
if (tb[IFLA_VXLAN_LEARNING]) {
__u8 learning = rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]);
print_bool(PRINT_JSON, "learning", NULL, learning);
if (!learning)
print_bool(PRINT_FP, NULL, "nolearning ", true);
}
if (tb[IFLA_VXLAN_PROXY] && rta_getattr_u8(tb[IFLA_VXLAN_PROXY]))
fputs("proxy ", f);
print_bool(PRINT_ANY, "proxy", "proxy ", true);
if (tb[IFLA_VXLAN_RSC] && rta_getattr_u8(tb[IFLA_VXLAN_RSC]))
fputs("rsc ", f);
print_bool(PRINT_ANY, "rsc", "rsc ", true);
if (tb[IFLA_VXLAN_L2MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L2MISS]))
fputs("l2miss ", f);
print_bool(PRINT_ANY, "l2miss", "l2miss ", true);
if (tb[IFLA_VXLAN_L3MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L3MISS]))
fputs("l3miss ", f);
print_bool(PRINT_ANY, "l3miss", "l3miss ", true);
if (tb[IFLA_VXLAN_TOS] &&
(tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]))) {
if (tos == 1)
fprintf(f, "tos inherit ");
else
fprintf(f, "tos %#x ", tos);
if (is_json_context()) {
print_0xhex(PRINT_JSON, "tos", "%#x", tos);
} else {
if (tos == 1)
fprintf(f, "tos %s ", "inherit");
else
fprintf(f, "tos %#x ", tos);
}
}
if (tb[IFLA_VXLAN_TTL]) {
__u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]);
if (ttl)
fprintf(f, "ttl %d ", ttl);
print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
else
print_int(PRINT_JSON, "ttl", NULL, ttl);
}
if (tb[IFLA_VXLAN_LABEL]) {
__u32 label = rta_getattr_u32(tb[IFLA_VXLAN_LABEL]);
if (label)
fprintf(f, "flowlabel %#x ", ntohl(label));
print_0xhex(PRINT_ANY,
"label",
"flowlabel %#x ",
ntohl(label));
}
if (tb[IFLA_VXLAN_AGEING]) {
__u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]);
if (age == 0)
fprintf(f, "ageing none ");
print_uint(PRINT_ANY, "ageing", "ageing none ", 0);
else
fprintf(f, "ageing %u ", age);
print_uint(PRINT_ANY, "ageing", "ageing %u ", age);
}
if (tb[IFLA_VXLAN_LIMIT] &&
((maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT])) != 0))
fprintf(f, "maxaddr %u ", maxaddr);
print_uint(PRINT_ANY, "limit", "maxaddr %u ", maxaddr);
if (tb[IFLA_VXLAN_UDP_CSUM]) {
if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM]))
fputs("no", f);
fputs("udpcsum ", f);
__u8 udp_csum = rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM]);
if (is_json_context()) {
print_bool(PRINT_ANY, "udp_csum", NULL, udp_csum);
} else {
if (!udp_csum)
fputs("no", f);
fputs("udpcsum ", f);
}
}
if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]) {
if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]))
fputs("no", f);
fputs("udp6zerocsumtx ", f);
__u8 csum6 = rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]);
if (is_json_context()) {
print_bool(PRINT_ANY,
"udp_zero_csum6_tx", NULL, csum6);
} else {
if (!csum6)
fputs("no", f);
fputs("udp6zerocsumtx ", f);
}
}
if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]) {
if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
fputs("no", f);
fputs("udp6zerocsumrx ", f);
__u8 csum6 = rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]);
if (is_json_context()) {
print_bool(PRINT_ANY,
"udp_zero_csum6_rx",
NULL,
csum6);
} else {
if (!csum6)
fputs("no", f);
fputs("udp6zerocsumrx ", f);
}
}
if (tb[IFLA_VXLAN_REMCSUM_TX] &&
rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_TX]))
fputs("remcsumtx ", f);
print_bool(PRINT_ANY, "remcsum_tx", "remcsumtx ", true);
if (tb[IFLA_VXLAN_REMCSUM_RX] &&
rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_RX]))
fputs("remcsumrx ", f);
print_bool(PRINT_ANY, "remcsum_rx", "remcsumrx ", true);
if (tb[IFLA_VXLAN_COLLECT_METADATA] &&
rta_getattr_u8(tb[IFLA_VXLAN_COLLECT_METADATA]))
fputs("external ", f);
print_bool(PRINT_ANY, "collect_metadata", "external ", true);
if (tb[IFLA_VXLAN_GBP])
fputs("gbp ", f);
print_bool(PRINT_ANY, "gbp", "gbp ", true);
if (tb[IFLA_VXLAN_GPE])
fputs("gpe ", f);
print_bool(PRINT_ANY, "gpe", "gpe ", true);
}
static void vxlan_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
print_explain(f);
}

View File

@ -16,6 +16,7 @@
#include "xdp.h"
#include "bpf_util.h"
#include "ip_common.h"
extern int force;
@ -93,30 +94,34 @@ void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
return;
mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
if (mode == XDP_ATTACHED_NONE)
return;
else if (details && link)
fprintf(fp, "%s prog/xdp", _SL_);
else if (mode == XDP_ATTACHED_DRV)
fprintf(fp, "xdp");
else if (mode == XDP_ATTACHED_SKB)
fprintf(fp, "xdpgeneric");
else if (mode == XDP_ATTACHED_HW)
fprintf(fp, "xdpoffload");
else
fprintf(fp, "xdp[%u]", mode);
if (is_json_context()) {
print_uint(PRINT_JSON, "attached", NULL, mode);
} else {
if (mode == XDP_ATTACHED_NONE)
return;
else if (details && link)
fprintf(fp, "%s prog/xdp", _SL_);
else if (mode == XDP_ATTACHED_DRV)
fprintf(fp, "xdp");
else if (mode == XDP_ATTACHED_SKB)
fprintf(fp, "xdpgeneric");
else if (mode == XDP_ATTACHED_HW)
fprintf(fp, "xdpoffload");
else
fprintf(fp, "xdp[%u]", mode);
if (tb[IFLA_XDP_PROG_ID])
prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
if (!details) {
if (prog_id && !link)
fprintf(fp, "/id:%u", prog_id);
fprintf(fp, " ");
return;
}
if (tb[IFLA_XDP_PROG_ID])
prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
if (!details) {
if (prog_id && !link)
fprintf(fp, "/id:%u", prog_id);
fprintf(fp, " ");
return;
}
if (prog_id) {
fprintf(fp, " ");
bpf_dump_prog_info(fp, prog_id);
if (prog_id) {
fprintf(fp, " ");
bpf_dump_prog_info(fp, prog_id);
}
}
}

View File

@ -561,9 +561,14 @@ static int validate_secy_dump(struct rtattr **attrs)
static void print_flag(FILE *f, struct rtattr *attrs[], const char *desc,
int field)
{
if (attrs[field])
fprintf(f, "%s %s ", desc,
values_on_off[!!rta_getattr_u8(attrs[field])]);
if (attrs[field]) {
const char *v = values_on_off[!!rta_getattr_u8(attrs[field])];
if (is_json_context())
print_string(PRINT_JSON, desc, NULL, v);
else
fprintf(f, "%s %s ", desc, v);
}
}
#define DEFAULT_CIPHER_NAME "GCM-AES-128"
@ -1017,8 +1022,16 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
return;
if (tb[IFLA_MACSEC_SCI]) {
fprintf(f, "sci %016llx ",
ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI])));
if (is_json_context()) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "%016llx",
ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI])));
print_string(PRINT_JSON, "sci", NULL, b1);
} else {
fprintf(f, "sci %016llx ",
ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI])));
}
}
print_flag(f, tb, "protect", IFLA_MACSEC_PROTECT);
@ -1026,35 +1039,70 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if (tb[IFLA_MACSEC_CIPHER_SUITE]) {
__u64 csid = rta_getattr_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
fprintf(f, "cipher %s ", cs_id_to_name(csid));
print_string(PRINT_ANY,
"cipher_suite",
"cipher %s ",
cs_id_to_name(csid));
}
if (tb[IFLA_MACSEC_ICV_LEN]) {
fprintf(f, "icvlen %hhu ",
rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN]));
if (is_json_context()) {
char b2[4];
snprintf(b2, sizeof(b2), "%hhu",
rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN]));
print_uint(PRINT_JSON, "icv_len", NULL, atoi(b2));
} else {
fprintf(f, "icvlen %hhu ",
rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN]));
}
}
if (tb[IFLA_MACSEC_ENCODING_SA]) {
fprintf(f, "encodingsa %hhu ",
rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA]));
if (is_json_context()) {
char b2[4];
snprintf(b2, sizeof(b2), "%hhu",
rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA]));
print_uint(PRINT_JSON, "encoding_sa", NULL, atoi(b2));
} else {
fprintf(f, "encodingsa %hhu ",
rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA]));
}
}
if (tb[IFLA_MACSEC_VALIDATION]) {
__u8 val = rta_getattr_u8(tb[IFLA_MACSEC_VALIDATION]);
fprintf(f, "validate %s ", VALIDATE_STR[val]);
print_string(PRINT_ANY,
"validation",
"validate %s ",
VALIDATE_STR[val]);
}
const char *inc_sci, *es, *replay;
if (is_json_context()) {
inc_sci = "inc_sci";
replay = "replay_protect";
es = "es";
} else {
inc_sci = "send_sci";
es = "end_station";
replay = "replay";
}
print_flag(f, tb, "encrypt", IFLA_MACSEC_ENCRYPT);
print_flag(f, tb, "send_sci", IFLA_MACSEC_INC_SCI);
print_flag(f, tb, "end_station", IFLA_MACSEC_ES);
print_flag(f, tb, inc_sci, IFLA_MACSEC_INC_SCI);
print_flag(f, tb, es, IFLA_MACSEC_ES);
print_flag(f, tb, "scb", IFLA_MACSEC_SCB);
print_flag(f, tb, replay, IFLA_MACSEC_REPLAY_PROTECT);
print_flag(f, tb, "replay", IFLA_MACSEC_REPLAY_PROTECT);
if (tb[IFLA_MACSEC_WINDOW]) {
fprintf(f, "window %d ",
rta_getattr_u32(tb[IFLA_MACSEC_WINDOW]));
}
if (tb[IFLA_MACSEC_WINDOW])
print_int(PRINT_ANY,
"window",
"window %d ",
rta_getattr_u32(tb[IFLA_MACSEC_WINDOW]));
}
static bool check_txsc_flags(bool es, bool scb, bool sci)

View File

@ -100,7 +100,7 @@ static void usage(void)
fprintf(stderr, "TIME := NUMBER[s|ms]\n");
fprintf(stderr, "BOOL := [1|0]\n");
fprintf(stderr, "FEATURES := ecn\n");
fprintf(stderr, "ENCAPTYPE := [ mpls | ip | ip6 | seg6 ]\n");
fprintf(stderr, "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local ]\n");
fprintf(stderr, "ENCAPHDR := [ MPLSLABEL | SEG6HDR ]\n");
fprintf(stderr, "SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n");
fprintf(stderr, "SEGMODE := [ encap | inline ]\n");
@ -698,6 +698,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
fprintf(fp, "onlink ");
if (nh->rtnh_flags & RTNH_F_PERVASIVE)
fprintf(fp, "pervasive ");
if (nh->rtnh_flags & RTNH_F_OFFLOAD)
fprintf(fp, "offload ");
if (nh->rtnh_flags & RTNH_F_LINKDOWN)
fprintf(fp, "linkdown ");
len -= NLMSG_ALIGN(nh->rtnh_len);

View File

@ -29,6 +29,8 @@
#include <linux/seg6.h>
#include <linux/seg6_iptunnel.h>
#include <linux/seg6_hmac.h>
#include <linux/seg6_local.h>
#include <net/if.h>
static const char *format_encap_type(int type)
{
@ -45,6 +47,8 @@ static const char *format_encap_type(int type)
return "bpf";
case LWTUNNEL_ENCAP_SEG6:
return "seg6";
case LWTUNNEL_ENCAP_SEG6_LOCAL:
return "seg6local";
default:
return "unknown";
}
@ -77,30 +81,18 @@ static int read_encap_type(const char *name)
return LWTUNNEL_ENCAP_BPF;
else if (strcmp(name, "seg6") == 0)
return LWTUNNEL_ENCAP_SEG6;
else if (strcmp(name, "seg6local") == 0)
return LWTUNNEL_ENCAP_SEG6_LOCAL;
else if (strcmp(name, "help") == 0)
encap_type_usage();
return LWTUNNEL_ENCAP_NONE;
}
static void print_encap_seg6(FILE *fp, struct rtattr *encap)
static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh)
{
struct rtattr *tb[SEG6_IPTUNNEL_MAX+1];
struct seg6_iptunnel_encap *tuninfo;
struct ipv6_sr_hdr *srh;
int i;
parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap);
if (!tb[SEG6_IPTUNNEL_SRH])
return;
tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
fprintf(fp, "mode %s ",
(tuninfo->mode == SEG6_IPTUN_MODE_ENCAP) ? "encap" : "inline");
srh = tuninfo->srh;
fprintf(fp, "segs %d [ ", srh->first_segment + 1);
for (i = srh->first_segment; i >= 0; i--)
@ -118,6 +110,136 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap)
}
}
static const char *seg6_mode_types[] = {
[SEG6_IPTUN_MODE_INLINE] = "inline",
[SEG6_IPTUN_MODE_ENCAP] = "encap",
[SEG6_IPTUN_MODE_L2ENCAP] = "l2encap",
};
static const char *format_seg6mode_type(int mode)
{
if (mode < 0 || mode > ARRAY_SIZE(seg6_mode_types))
return "<unknown>";
return seg6_mode_types[mode];
}
static int read_seg6mode_type(const char *mode)
{
int i;
for (i = 0; i < ARRAY_SIZE(seg6_mode_types); i++) {
if (strcmp(mode, seg6_mode_types[i]) == 0)
return i;
}
return -1;
}
static void print_encap_seg6(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[SEG6_IPTUNNEL_MAX+1];
struct seg6_iptunnel_encap *tuninfo;
parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap);
if (!tb[SEG6_IPTUNNEL_SRH])
return;
tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
fprintf(fp, "mode %s ", format_seg6mode_type(tuninfo->mode));
print_srh(fp, tuninfo->srh);
}
static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
[SEG6_LOCAL_ACTION_END] = "End",
[SEG6_LOCAL_ACTION_END_X] = "End.X",
[SEG6_LOCAL_ACTION_END_T] = "End.T",
[SEG6_LOCAL_ACTION_END_DX2] = "End.DX2",
[SEG6_LOCAL_ACTION_END_DX6] = "End.DX6",
[SEG6_LOCAL_ACTION_END_DX4] = "End.DX4",
[SEG6_LOCAL_ACTION_END_DT6] = "End.DT6",
[SEG6_LOCAL_ACTION_END_DT4] = "End.DT4",
[SEG6_LOCAL_ACTION_END_B6] = "End.B6",
[SEG6_LOCAL_ACTION_END_B6_ENCAP] = "End.B6.Encaps",
[SEG6_LOCAL_ACTION_END_BM] = "End.BM",
[SEG6_LOCAL_ACTION_END_S] = "End.S",
[SEG6_LOCAL_ACTION_END_AS] = "End.AS",
[SEG6_LOCAL_ACTION_END_AM] = "End.AM",
};
static const char *format_action_type(int action)
{
if (action < 0 || action > SEG6_LOCAL_ACTION_MAX)
return "<invalid>";
return seg6_action_names[action] ?: "<unknown>";
}
static int read_action_type(const char *name)
{
int i;
for (i = 0; i < SEG6_LOCAL_ACTION_MAX + 1; i++) {
if (!seg6_action_names[i])
continue;
if (strcmp(seg6_action_names[i], name) == 0)
return i;
}
return SEG6_LOCAL_ACTION_UNSPEC;
}
static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[SEG6_LOCAL_MAX + 1];
char ifbuf[IFNAMSIZ];
int action;
parse_rtattr_nested(tb, SEG6_LOCAL_MAX, encap);
if (!tb[SEG6_LOCAL_ACTION])
return;
action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]);
fprintf(fp, "action %s ", format_action_type(action));
if (tb[SEG6_LOCAL_SRH]) {
fprintf(fp, "srh ");
print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
}
if (tb[SEG6_LOCAL_TABLE])
fprintf(fp, "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
if (tb[SEG6_LOCAL_NH4]) {
fprintf(fp, "nh4 %s ",
rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
}
if (tb[SEG6_LOCAL_NH6]) {
fprintf(fp, "nh6 %s ",
rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
}
if (tb[SEG6_LOCAL_IIF]) {
int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]);
fprintf(fp, "iif %s ",
if_indextoname(iif, ifbuf) ?: "<unknown>");
}
if (tb[SEG6_LOCAL_OIF]) {
int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
fprintf(fp, "oif %s ",
if_indextoname(oif, ifbuf) ?: "<unknown>");
}
}
static void print_encap_mpls(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
@ -287,56 +409,20 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
case LWTUNNEL_ENCAP_SEG6:
print_encap_seg6(fp, encap);
break;
case LWTUNNEL_ENCAP_SEG6_LOCAL:
print_encap_seg6local(fp, encap);
break;
}
}
static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
char ***argvp)
static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
{
int mode_ok = 0, segs_ok = 0, hmac_ok = 0;
struct seg6_iptunnel_encap *tuninfo;
struct ipv6_sr_hdr *srh;
char **argv = *argvp;
char segbuf[1024];
int argc = *argcp;
int encap = -1;
__u32 hmac = 0;
int nsegs = 0;
int srhlen;
char *s;
int i;
while (argc > 0) {
if (strcmp(*argv, "mode") == 0) {
NEXT_ARG();
if (mode_ok++)
duparg2("mode", *argv);
if (strcmp(*argv, "encap") == 0)
encap = 1;
else if (strcmp(*argv, "inline") == 0)
encap = 0;
else
invarg("\"mode\" value is invalid\n", *argv);
} else if (strcmp(*argv, "segs") == 0) {
NEXT_ARG();
if (segs_ok++)
duparg2("segs", *argv);
if (encap == -1)
invarg("\"segs\" provided before \"mode\"\n",
*argv);
strlcpy(segbuf, *argv, 1024);
} else if (strcmp(*argv, "hmac") == 0) {
NEXT_ARG();
if (hmac_ok++)
duparg2("hmac", *argv);
get_u32(&hmac, *argv, 0);
} else {
break;
}
argc--; argv++;
}
s = segbuf;
for (i = 0; *s; *s++ == ',' ? i++ : *s);
nsegs = i + 1;
@ -349,15 +435,9 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
if (hmac)
srhlen += 40;
tuninfo = malloc(sizeof(*tuninfo) + srhlen);
memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
srh = malloc(srhlen);
memset(srh, 0, srhlen);
if (encap)
tuninfo->mode = SEG6_IPTUN_MODE_ENCAP;
else
tuninfo->mode = SEG6_IPTUN_MODE_INLINE;
srh = tuninfo->srh;
srh->hdrlen = (srhlen >> 3) - 1;
srh->type = 4;
srh->segments_left = nsegs - 1;
@ -381,9 +461,173 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
tlv->hmackeyid = htonl(hmac);
}
return srh;
}
static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
char ***argvp)
{
int mode_ok = 0, segs_ok = 0, hmac_ok = 0;
struct seg6_iptunnel_encap *tuninfo;
struct ipv6_sr_hdr *srh;
char **argv = *argvp;
char segbuf[1024];
int argc = *argcp;
int encap = -1;
__u32 hmac = 0;
int srhlen;
while (argc > 0) {
if (strcmp(*argv, "mode") == 0) {
NEXT_ARG();
if (mode_ok++)
duparg2("mode", *argv);
encap = read_seg6mode_type(*argv);
if (encap < 0)
invarg("\"mode\" value is invalid\n", *argv);
} else if (strcmp(*argv, "segs") == 0) {
NEXT_ARG();
if (segs_ok++)
duparg2("segs", *argv);
if (encap == -1)
invarg("\"segs\" provided before \"mode\"\n",
*argv);
strlcpy(segbuf, *argv, 1024);
} else if (strcmp(*argv, "hmac") == 0) {
NEXT_ARG();
if (hmac_ok++)
duparg2("hmac", *argv);
get_u32(&hmac, *argv, 0);
} else {
break;
}
argc--; argv++;
}
srh = parse_srh(segbuf, hmac, encap);
srhlen = (srh->hdrlen + 1) << 3;
tuninfo = malloc(sizeof(*tuninfo) + srhlen);
memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
tuninfo->mode = encap;
memcpy(tuninfo->srh, srh, srhlen);
rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
sizeof(*tuninfo) + srhlen);
free(tuninfo);
free(srh);
*argcp = argc + 1;
*argvp = argv - 1;
return 0;
}
static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
char ***argvp)
{
int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0;
__u32 action = 0, table, iif, oif;
struct ipv6_sr_hdr *srh;
char **argv = *argvp;
int argc = *argcp;
char segbuf[1024];
inet_prefix addr;
__u32 hmac = 0;
while (argc > 0) {
if (strcmp(*argv, "action") == 0) {
NEXT_ARG();
if (action_ok++)
duparg2("action", *argv);
action = read_action_type(*argv);
if (!action)
invarg("\"action\" value is invalid\n", *argv);
rta_addattr32(rta, len, SEG6_LOCAL_ACTION, action);
} else if (strcmp(*argv, "table") == 0) {
NEXT_ARG();
if (table_ok++)
duparg2("table", *argv);
get_u32(&table, *argv, 0);
rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
} else if (strcmp(*argv, "nh4") == 0) {
NEXT_ARG();
if (nh4_ok++)
duparg2("nh4", *argv);
get_addr(&addr, *argv, AF_INET);
rta_addattr_l(rta, len, SEG6_LOCAL_NH4, &addr.data,
addr.bytelen);
} else if (strcmp(*argv, "nh6") == 0) {
NEXT_ARG();
if (nh6_ok++)
duparg2("nh6", *argv);
get_addr(&addr, *argv, AF_INET6);
rta_addattr_l(rta, len, SEG6_LOCAL_NH6, &addr.data,
addr.bytelen);
} else if (strcmp(*argv, "iif") == 0) {
NEXT_ARG();
if (iif_ok++)
duparg2("iif", *argv);
iif = if_nametoindex(*argv);
if (!iif)
invarg("\"iif\" interface not found\n", *argv);
rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
} else if (strcmp(*argv, "oif") == 0) {
NEXT_ARG();
if (oif_ok++)
duparg2("oif", *argv);
oif = if_nametoindex(*argv);
if (!oif)
invarg("\"oif\" interface not found\n", *argv);
rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
} else if (strcmp(*argv, "srh") == 0) {
NEXT_ARG();
if (srh_ok++)
duparg2("srh", *argv);
if (strcmp(*argv, "segs") != 0)
invarg("missing \"segs\" attribute for srh\n",
*argv);
NEXT_ARG();
if (segs_ok++)
duparg2("segs", *argv);
strncpy(segbuf, *argv, 1024);
segbuf[1023] = 0;
if (!NEXT_ARG_OK())
break;
NEXT_ARG();
if (strcmp(*argv, "hmac") == 0) {
NEXT_ARG();
if (hmac_ok++)
duparg2("hmac", *argv);
get_u32(&hmac, *argv, 0);
} else {
continue;
}
} else {
break;
}
argc--; argv++;
}
if (!action) {
fprintf(stderr, "Missing action type\n");
exit(-1);
}
if (srh_ok) {
int srhlen;
srh = parse_srh(segbuf, hmac,
action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
srhlen = (srh->hdrlen + 1) << 3;
rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
free(srh);
}
*argcp = argc + 1;
*argvp = argv - 1;
@ -751,6 +995,9 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
case LWTUNNEL_ENCAP_SEG6:
parse_encap_seg6(rta, len, &argc, &argv);
break;
case LWTUNNEL_ENCAP_SEG6_LOCAL:
parse_encap_seg6local(rta, len, &argc, &argv);
break;
default:
fprintf(stderr, "Error: unsupported encap type\n");
break;

View File

@ -26,7 +26,7 @@
static void print_usage(FILE *f)
{
fprintf(f,
"Usage: ... { gre | gretap } [ remote ADDR ]\n"
"Usage: ... { gre | gretap | erspan } [ remote ADDR ]\n"
" [ local ADDR ]\n"
" [ [i|o]seq ]\n"
" [ [i|o]key KEY ]\n"
@ -44,6 +44,7 @@ static void print_usage(FILE *f)
" [ [no]encap-csum6 ]\n"
" [ [no]encap-remcsum ]\n"
" [ fwmark MARK ]\n"
" [ erspan IDX ]\n"
"\n"
"Where: ADDR := { IP_ADDRESS | any }\n"
" TOS := { NUMBER | inherit }\n"
@ -96,6 +97,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
__u8 metadata = 0;
__u8 ignore_df = 0;
__u32 fwmark = 0;
__u32 erspan_idx = 0;
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
@ -172,6 +174,9 @@ get_failed:
if (greinfo[IFLA_GRE_FWMARK])
fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]);
if (greinfo[IFLA_GRE_ERSPAN_INDEX])
erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]);
}
while (argc > 0) {
@ -328,6 +333,12 @@ get_failed:
NEXT_ARG();
if (get_u32(&fwmark, *argv, 0))
invarg("invalid fwmark\n", *argv);
} else if (strcmp(*argv, "erspan") == 0) {
NEXT_ARG();
if (get_u32(&erspan_idx, *argv, 0))
invarg("invalid erspan index\n", *argv);
if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0)
invarg("erspan index must be > 0 and <= 20-bit\n", *argv);
} else
usage();
argc--; argv++;
@ -359,6 +370,8 @@ get_failed:
addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
if (erspan_idx != 0)
addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
} else {
addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
}
@ -389,7 +402,7 @@ static void gre_print_direct_opt(FILE *f, struct rtattr *tb[])
remote = format_host(AF_INET, 4, &addr);
}
fprintf(f, "remote %s ", remote);
print_string(PRINT_ANY, "remote", "remote %s ", remote);
if (tb[IFLA_GRE_LOCAL]) {
unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]);
@ -398,36 +411,52 @@ static void gre_print_direct_opt(FILE *f, struct rtattr *tb[])
local = format_host(AF_INET, 4, &addr);
}
fprintf(f, "local %s ", local);
print_string(PRINT_ANY, "local", "local %s ", local);
if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
const char *n = if_indextoname(link, s2);
if (n)
fprintf(f, "dev %s ", n);
print_string(PRINT_ANY, "link", "dev %s ", n);
else
fprintf(f, "dev %u ", link);
print_uint(PRINT_ANY, "link_index", "dev %u ", link);
}
if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
else
fprintf(f, "ttl inherit ");
if (tb[IFLA_GRE_TTL]) {
__u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]);
if (ttl)
print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
else
print_int(PRINT_JSON, "ttl", NULL, ttl);
} else {
print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
}
if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) {
int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);
fputs("tos ", f);
if (tos == 1)
fputs("inherit ", f);
else
fprintf(f, "0x%x ", tos);
if (is_json_context()) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "0x%x", tos);
print_string(PRINT_JSON, "tos", NULL, b1);
} else {
fputs("tos ", f);
if (tos == 1)
fputs("inherit ", f);
else
fprintf(f, "0x%x ", tos);
}
}
if (tb[IFLA_GRE_PMTUDISC] &&
!rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
fputs("nopmtudisc ", f);
if (tb[IFLA_GRE_PMTUDISC]) {
if (!rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
else
print_bool(PRINT_JSON, "pmtudisc", NULL, true);
}
if (tb[IFLA_GRE_IFLAGS])
iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
@ -437,26 +466,31 @@ static void gre_print_direct_opt(FILE *f, struct rtattr *tb[])
if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
fprintf(f, "ikey %s ", s2);
print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
}
if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
fprintf(f, "okey %s ", s2);
print_string(PRINT_ANY, "okey", "okey %s ", s2);
}
if (iflags & GRE_SEQ)
fputs("iseq ", f);
print_bool(PRINT_ANY, "iseq", "iseq ", true);
if (oflags & GRE_SEQ)
fputs("oseq ", f);
print_bool(PRINT_ANY, "oseq", "oseq ", true);
if (iflags & GRE_CSUM)
fputs("icsum ", f);
print_bool(PRINT_ANY, "icsum", "icsum ", true);
if (oflags & GRE_CSUM)
fputs("ocsum ", f);
print_bool(PRINT_ANY, "ocsum", "ocsum ", true);
if (tb[IFLA_GRE_FWMARK] && rta_getattr_u32(tb[IFLA_GRE_FWMARK])) {
fprintf(f, "fwmark 0x%x ",
rta_getattr_u32(tb[IFLA_GRE_FWMARK]));
if (tb[IFLA_GRE_FWMARK]) {
__u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]);
if (fwmark) {
snprintf(s2, sizeof(s2), "0x%x", fwmark);
print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
}
}
}
@ -468,10 +502,16 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if (!tb[IFLA_GRE_COLLECT_METADATA])
gre_print_direct_opt(f, tb);
else
fputs("external ", f);
print_bool(PRINT_ANY, "external", "external ", true);
if (tb[IFLA_GRE_IGNORE_DF] && rta_getattr_u8(tb[IFLA_GRE_IGNORE_DF]))
fputs("ignore-df ", f);
print_bool(PRINT_ANY, "ignore_df", "ignore-df ", true);
if (tb[IFLA_GRE_ERSPAN_INDEX]) {
__u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
fprintf(f, "erspan_index %u ", erspan_idx);
}
if (tb[IFLA_GRE_ENCAP_TYPE] &&
rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
@ -480,45 +520,73 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
__u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]);
__u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]);
fputs("encap ", f);
open_json_object("encap");
print_string(PRINT_FP, NULL, "encap ", NULL);
switch (type) {
case TUNNEL_ENCAP_FOU:
fputs("fou ", f);
print_string(PRINT_ANY, "type", "%s ", "fou");
break;
case TUNNEL_ENCAP_GUE:
fputs("gue ", f);
print_string(PRINT_ANY, "type", "%s ", "gue");
break;
default:
fputs("unknown ", f);
print_null(PRINT_ANY, "type", "%s ", "unknown");
break;
}
if (sport == 0)
fputs("encap-sport auto ", f);
else
fprintf(f, "encap-sport %u", ntohs(sport));
if (is_json_context()) {
print_uint(PRINT_JSON,
"sport",
NULL,
sport ? ntohs(sport) : 0);
print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
fprintf(f, "encap-dport %u ", ntohs(dport));
print_bool(PRINT_JSON,
"csum",
NULL,
flags & TUNNEL_ENCAP_FLAG_CSUM);
if (flags & TUNNEL_ENCAP_FLAG_CSUM)
fputs("encap-csum ", f);
else
fputs("noencap-csum ", f);
print_bool(PRINT_JSON,
"csum6",
NULL,
flags & TUNNEL_ENCAP_FLAG_CSUM6);
if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
print_bool(PRINT_JSON,
"remcsum",
NULL,
flags & TUNNEL_ENCAP_FLAG_REMCSUM);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
close_json_object();
} else {
if (sport == 0)
fputs("encap-sport auto ", f);
else
fprintf(f, "encap-sport %u", ntohs(sport));
fprintf(f, "encap-dport %u ", ntohs(dport));
if (flags & TUNNEL_ENCAP_FLAG_CSUM)
fputs("encap-csum ", f);
else
fputs("noencap-csum ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
}
}
}
static void gre_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
print_usage(f);
}
@ -538,3 +606,11 @@ struct link_util gretap_link_util = {
.print_opt = gre_print_opt,
.print_help = gre_print_help,
};
struct link_util erspan_link_util = {
.id = "erspan",
.maxattr = IFLA_GRE_MAX,
.parse_opt = gre_parse_opt,
.print_opt = gre_print_opt,
.print_help = gre_print_help,
};

View File

@ -425,7 +425,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
remote = format_host(AF_INET6, sizeof(addr), &addr);
}
fprintf(f, "remote %s ", remote);
print_string(PRINT_ANY, "remote", "remote %s ", remote);
if (tb[IFLA_GRE_LOCAL]) {
struct in6_addr addr;
@ -436,43 +436,83 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
local = format_host(AF_INET6, sizeof(addr), &addr);
}
fprintf(f, "local %s ", local);
print_string(PRINT_ANY, "local", "local %s ", local);
if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
const char *n = if_indextoname(link, s2);
if (n)
fprintf(f, "dev %s ", n);
print_string(PRINT_ANY, "link", "dev %s ", n);
else
fprintf(f, "dev %u ", link);
print_uint(PRINT_ANY, "link_index", "dev %u ", link);
}
if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
fprintf(f, "hoplimit %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
if (tb[IFLA_GRE_TTL]) {
__u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]);
if (ttl)
print_int(PRINT_ANY, "ttl", "hoplimit %d ", ttl);
else
print_int(PRINT_JSON, "ttl", NULL, ttl);
}
if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
fprintf(f, "encaplimit none ");
print_bool(PRINT_ANY,
"ip6_tnl_f_ign_encap_limit",
"encaplimit none ",
true);
else if (tb[IFLA_GRE_ENCAP_LIMIT]) {
int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]);
fprintf(f, "encaplimit %d ", encap_limit);
print_int(PRINT_ANY,
"encap_limit",
"encaplimit %d ",
encap_limit);
}
if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
fprintf(f, "flowlabel inherit ");
else
fprintf(f, "flowlabel 0x%05x ",
ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) {
print_bool(PRINT_ANY,
"ip6_tnl_f_use_orig_flowlabel",
"flowlabel inherit ",
true);
} else {
if (is_json_context()) {
SPRINT_BUF(b1);
if (flags & IP6_TNL_F_USE_ORIG_TCLASS)
fprintf(f, "tclass inherit ");
else
fprintf(f, "tclass 0x%02x ",
ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20);
snprintf(b1, sizeof(b1), "0x%05x",
ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
print_string(PRINT_JSON, "flowlabel", NULL, b1);
} else {
fprintf(f, "flowlabel 0x%05x ",
ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
}
}
if (flags & IP6_TNL_F_USE_ORIG_TCLASS) {
print_bool(PRINT_ANY,
"ip6_tnl_f_use_orig_tclass",
"tclass inherit ",
true);
} else {
if (is_json_context()) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "0x%05x",
ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20);
print_string(PRINT_JSON, "tclass", NULL, b1);
} else {
fprintf(f, "tclass 0x%02x ",
ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20);
}
}
if (flags & IP6_TNL_F_RCV_DSCP_COPY)
fprintf(f, "dscp inherit ");
print_bool(PRINT_ANY,
"ip6_tnl_f_rcv_dscp_copy",
"dscp inherit ",
true);
if (tb[IFLA_GRE_IFLAGS])
iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
@ -482,27 +522,37 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
fprintf(f, "ikey %s ", s2);
print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
}
if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
fprintf(f, "okey %s ", s2);
print_string(PRINT_ANY, "okey", "okey %s ", s2);
}
if (iflags & GRE_SEQ)
fputs("iseq ", f);
print_bool(PRINT_ANY, "iseq", "iseq ", true);
if (oflags & GRE_SEQ)
fputs("oseq ", f);
print_bool(PRINT_ANY, "oseq", "oseq ", true);
if (iflags & GRE_CSUM)
fputs("icsum ", f);
print_bool(PRINT_ANY, "icsum", "icsum ", true);
if (oflags & GRE_CSUM)
fputs("ocsum ", f);
print_bool(PRINT_ANY, "ocsum", "ocsum ", true);
if (flags & IP6_TNL_F_USE_ORIG_FWMARK)
fprintf(f, "fwmark inherit ");
else if (tb[IFLA_GRE_FWMARK] && rta_getattr_u32(tb[IFLA_GRE_FWMARK]))
fprintf(f, "fwmark 0x%x ", rta_getattr_u32(tb[IFLA_GRE_FWMARK]));
print_bool(PRINT_ANY,
"ip6_tnl_f_use_orig_fwmark",
"fwmark inherit ",
true);
else if (tb[IFLA_GRE_FWMARK]) {
__u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]);
if (fwmark) {
snprintf(s2, sizeof(s2), "0x%x", fwmark);
print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
}
}
if (tb[IFLA_GRE_ENCAP_TYPE] &&
rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
@ -511,40 +561,57 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
__u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]);
__u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]);
fputs("encap ", f);
open_json_object("encap");
print_string(PRINT_FP, NULL, "encap ", NULL);
switch (type) {
case TUNNEL_ENCAP_FOU:
fputs("fou ", f);
print_string(PRINT_ANY, "type", "%s ", "fou");
break;
case TUNNEL_ENCAP_GUE:
fputs("gue ", f);
print_string(PRINT_ANY, "type", "%s ", "gue");
break;
default:
fputs("unknown ", f);
print_null(PRINT_ANY, "type", "unknown ", NULL);
break;
}
if (sport == 0)
fputs("encap-sport auto ", f);
else
fprintf(f, "encap-sport %u", ntohs(sport));
if (is_json_context()) {
print_uint(PRINT_JSON,
"sport",
NULL,
sport ? ntohs(sport) : 0);
print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
print_bool(PRINT_JSON, "csum", NULL,
flags & TUNNEL_ENCAP_FLAG_CSUM);
print_bool(PRINT_JSON, "csum6", NULL,
flags & TUNNEL_ENCAP_FLAG_CSUM6);
print_bool(PRINT_JSON, "remcsum", NULL,
flags & TUNNEL_ENCAP_FLAG_REMCSUM);
close_json_object();
} else {
if (sport == 0)
fputs("encap-sport auto ", f);
else
fprintf(f, "encap-sport %u", ntohs(sport));
fprintf(f, "encap-dport %u ", ntohs(dport));
fprintf(f, "encap-dport %u ", ntohs(dport));
if (flags & TUNNEL_ENCAP_FLAG_CSUM)
fputs("encap-csum ", f);
else
fputs("noencap-csum ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM)
fputs("encap-csum ", f);
else
fputs("noencap-csum ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
}
}
}

View File

@ -346,25 +346,29 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
if (tb[IFLA_IPTUN_PROTO]) {
switch (rta_getattr_u8(tb[IFLA_IPTUN_PROTO])) {
case IPPROTO_IPIP:
fprintf(f, "ipip6 ");
print_string(PRINT_ANY, "proto", "%s ", "ipip6");
break;
case IPPROTO_IPV6:
fprintf(f, "ip6ip6 ");
print_string(PRINT_ANY, "proto", "%s ", "ip6ip6");
break;
case 0:
fprintf(f, "any ");
print_string(PRINT_ANY, "proto", "%s ", "any");
break;
}
}
if (tb[IFLA_IPTUN_REMOTE]) {
fprintf(f, "remote %s ",
rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_REMOTE]));
print_string(PRINT_ANY,
"remote",
"remote %s ",
rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_REMOTE]));
}
if (tb[IFLA_IPTUN_LOCAL]) {
fprintf(f, "local %s ",
rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_LOCAL]));
print_string(PRINT_ANY,
"local",
"local %s ",
rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_LOCAL]));
}
if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) {
@ -372,93 +376,161 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
const char *n = if_indextoname(link, s2);
if (n)
fprintf(f, "dev %s ", n);
print_string(PRINT_ANY, "link", "dev %s ", n);
else
fprintf(f, "dev %u ", link);
print_uint(PRINT_ANY, "link_index", "dev %u ", link);
}
if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
printf("encaplimit none ");
print_bool(PRINT_ANY,
"ip6_tnl_f_ign_encap_limit",
"encaplimit none ",
true);
else if (tb[IFLA_IPTUN_ENCAP_LIMIT])
fprintf(f, "encaplimit %u ",
rta_getattr_u8(tb[IFLA_IPTUN_ENCAP_LIMIT]));
print_uint(PRINT_ANY,
"encap_limit",
"encaplimit %u ",
rta_getattr_u8(tb[IFLA_IPTUN_ENCAP_LIMIT]));
if (tb[IFLA_IPTUN_TTL])
fprintf(f, "hoplimit %u ", rta_getattr_u8(tb[IFLA_IPTUN_TTL]));
print_uint(PRINT_ANY,
"ttl",
"hoplimit %u ",
rta_getattr_u8(tb[IFLA_IPTUN_TTL]));
if (flags & IP6_TNL_F_USE_ORIG_TCLASS)
printf("tclass inherit ");
print_bool(PRINT_ANY,
"ip6_tnl_f_use_orig_tclass",
"tclass inherit ",
true);
else if (tb[IFLA_IPTUN_FLOWINFO]) {
__u32 val = ntohl(flowinfo & IP6_FLOWINFO_TCLASS);
printf("tclass 0x%02x ", (__u8)(val >> 20));
if (is_json_context()) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "0x%02x", (__u8)(val >> 20));
print_string(PRINT_JSON, "flowinfo_tclass", NULL, b1);
} else {
printf("tclass 0x%02x ", (__u8)(val >> 20));
}
}
if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
printf("flowlabel inherit ");
else
printf("flowlabel 0x%05x ", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) {
print_bool(PRINT_ANY,
"ip6_tnl_f_use_orig_flowlabel",
"flowlabel inherit ",
true);
} else {
if (is_json_context()) {
SPRINT_BUF(b1);
printf("(flowinfo 0x%08x) ", ntohl(flowinfo));
snprintf(b1, sizeof(b1), "0x%05x",
ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
print_string(PRINT_JSON, "flowlabel", NULL, b1);
} else {
printf("flowlabel 0x%05x ",
ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
}
}
if (is_json_context()) {
SPRINT_BUF(flwinfo);
snprintf(flwinfo, sizeof(flwinfo), "0x%08x", ntohl(flowinfo));
print_string(PRINT_JSON, "flowinfo", NULL, flwinfo);
} else {
printf("(flowinfo 0x%08x) ", ntohl(flowinfo));
}
if (flags & IP6_TNL_F_RCV_DSCP_COPY)
printf("dscp inherit ");
print_bool(PRINT_ANY,
"ip6_tnl_f_rcv_dscp_copy",
"dscp inherit ",
true);
if (flags & IP6_TNL_F_MIP6_DEV)
fprintf(f, "mip6 ");
print_bool(PRINT_ANY, "ip6_tnl_f_mip6_dev", "mip6 ", true);
if (flags & IP6_TNL_F_USE_ORIG_FWMARK)
fprintf(f, "fwmark inherit ");
else if (tb[IFLA_IPTUN_FWMARK] && rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]))
fprintf(f, "fwmark 0x%x ", rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]));
if (flags & IP6_TNL_F_USE_ORIG_FWMARK) {
print_bool(PRINT_ANY,
"ip6_tnl_f_use_orig_fwmark",
"fwmark inherit ",
true);
} else if (tb[IFLA_IPTUN_FWMARK]) {
__u32 fwmark = rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]);
if (fwmark) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "0x%x", fwmark);
print_string(PRINT_ANY, "fwmark", "fwmark %s ", b1);
}
}
if (tb[IFLA_IPTUN_ENCAP_TYPE] &&
rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]) !=
TUNNEL_ENCAP_NONE) {
rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
__u16 type = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]);
__u16 flags = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_FLAGS]);
__u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]);
__u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]);
fputs("encap ", f);
open_json_object("encap");
print_string(PRINT_FP, NULL, "encap ", NULL);
switch (type) {
case TUNNEL_ENCAP_FOU:
fputs("fou ", f);
print_string(PRINT_ANY, "type", "%s ", "fou");
break;
case TUNNEL_ENCAP_GUE:
fputs("gue ", f);
print_string(PRINT_ANY, "type", "%s ", "gue");
break;
default:
fputs("unknown ", f);
print_null(PRINT_ANY, "type", "unknown ", NULL);
break;
}
if (sport == 0)
fputs("encap-sport auto ", f);
else
fprintf(f, "encap-sport %u", ntohs(sport));
if (is_json_context()) {
print_uint(PRINT_JSON,
"sport",
NULL,
sport ? ntohs(sport) : 0);
print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
print_bool(PRINT_JSON, "csum", NULL,
flags & TUNNEL_ENCAP_FLAG_CSUM);
print_bool(PRINT_JSON, "csum6", NULL,
flags & TUNNEL_ENCAP_FLAG_CSUM6);
print_bool(PRINT_JSON, "remcsum", NULL,
flags & TUNNEL_ENCAP_FLAG_REMCSUM);
close_json_object();
} else {
if (sport == 0)
fputs("encap-sport auto ", f);
else
fprintf(f, "encap-sport %u", ntohs(sport));
fprintf(f, "encap-dport %u ", ntohs(dport));
fprintf(f, "encap-dport %u ", ntohs(dport));
if (flags & TUNNEL_ENCAP_FLAG_CSUM)
fputs("encap-csum ", f);
else
fputs("noencap-csum ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM)
fputs("encap-csum ", f);
else
fputs("noencap-csum ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
}
}
}
static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv,
FILE *f)
FILE *f)
{
print_usage(f);
}

View File

@ -398,7 +398,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
remote = format_host(AF_INET, 4, &addr);
}
fprintf(f, "remote %s ", remote);
print_string(PRINT_ANY, "remote", "remote %s ", remote);
if (tb[IFLA_IPTUN_LOCAL]) {
unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]);
@ -407,43 +407,55 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
local = format_host(AF_INET, 4, &addr);
}
fprintf(f, "local %s ", local);
print_string(PRINT_ANY, "local", "local %s ", local);
if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) {
unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
const char *n = if_indextoname(link, s2);
if (n)
fprintf(f, "dev %s ", n);
print_string(PRINT_ANY, "link", "dev %s ", n);
else
fprintf(f, "dev %u ", link);
print_int(PRINT_ANY, "link_index", "dev %u ", link);
}
if (tb[IFLA_IPTUN_TTL] && rta_getattr_u8(tb[IFLA_IPTUN_TTL]))
fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_IPTUN_TTL]));
else
fprintf(f, "ttl inherit ");
if (tb[IFLA_IPTUN_TTL]) {
__u8 ttl = rta_getattr_u8(tb[IFLA_IPTUN_TTL]);
if (tb[IFLA_IPTUN_TOS] && rta_getattr_u8(tb[IFLA_IPTUN_TOS])) {
if (ttl)
print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
else
print_int(PRINT_JSON, "ttl", NULL, ttl);
} else {
print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
}
if (tb[IFLA_IPTUN_TOS]) {
int tos = rta_getattr_u8(tb[IFLA_IPTUN_TOS]);
fputs("tos ", f);
if (tos == 1)
fputs("inherit ", f);
else
fprintf(f, "0x%x ", tos);
if (tos) {
if (is_json_context()) {
print_0xhex(PRINT_JSON, "tos", "%#x", tos);
} else {
fputs("tos ", f);
if (tos == 1)
fputs("inherit ", f);
else
fprintf(f, "0x%x ", tos);
}
}
}
if (tb[IFLA_IPTUN_PMTUDISC] && rta_getattr_u8(tb[IFLA_IPTUN_PMTUDISC]))
fprintf(f, "pmtudisc ");
print_bool(PRINT_ANY, "pmtudisc", "pmtudisc ", true);
else
fprintf(f, "nopmtudisc ");
print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
if (tb[IFLA_IPTUN_FLAGS]) {
__u16 iflags = rta_getattr_u16(tb[IFLA_IPTUN_FLAGS]);
if (iflags & SIT_ISATAP)
fprintf(f, "isatap ");
print_bool(PRINT_ANY, "isatap", "isatap ", true);
}
if (tb[IFLA_IPTUN_6RD_PREFIXLEN] &&
@ -453,14 +465,32 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
__u32 relayprefix =
rta_getattr_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]);
printf("6rd-prefix %s/%u ",
inet_ntop(AF_INET6, RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]),
s1, sizeof(s1)),
prefixlen);
if (relayprefix) {
printf("6rd-relay_prefix %s/%u ",
format_host(AF_INET, 4, &relayprefix),
relayprefixlen);
const char *prefix = inet_ntop(AF_INET6,
RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]),
s1, sizeof(s1));
if (is_json_context()) {
print_string(PRINT_JSON, "prefix", NULL, prefix);
print_int(PRINT_JSON, "prefixlen", NULL, prefixlen);
if (relayprefix) {
print_string(PRINT_JSON,
"relay_prefix",
NULL,
format_host(AF_INET,
4,
&relayprefix));
print_int(PRINT_JSON,
"relay_prefixlen",
NULL,
relayprefixlen);
}
} else {
printf("6rd-prefix %s/%u ", prefix, prefixlen);
if (relayprefix) {
printf("6rd-relay_prefix %s/%u ",
format_host(AF_INET, 4, &relayprefix),
relayprefixlen);
}
}
}
@ -470,45 +500,72 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
__u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]);
__u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]);
fputs("encap ", f);
print_string(PRINT_FP, NULL, "encap ", NULL);
switch (type) {
case TUNNEL_ENCAP_FOU:
fputs("fou ", f);
print_string(PRINT_ANY, "type", "%s ", "fou");
break;
case TUNNEL_ENCAP_GUE:
fputs("gue ", f);
print_string(PRINT_ANY, "type", "%s ", "gue");
break;
default:
fputs("unknown ", f);
print_null(PRINT_ANY, "type", "unknown ", NULL);
break;
}
if (sport == 0)
fputs("encap-sport auto ", f);
else
fprintf(f, "encap-sport %u", ntohs(sport));
if (is_json_context()) {
print_uint(PRINT_JSON,
"sport",
NULL,
sport ? ntohs(sport) : 0);
print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
print_bool(PRINT_JSON,
"csum",
NULL,
flags & TUNNEL_ENCAP_FLAG_CSUM);
print_bool(PRINT_JSON,
"csum6",
NULL,
flags & TUNNEL_ENCAP_FLAG_CSUM6);
print_bool(PRINT_JSON,
"remcsum",
NULL,
flags & TUNNEL_ENCAP_FLAG_REMCSUM);
close_json_object();
} else {
if (sport == 0)
fputs("encap-sport auto ", f);
else
fprintf(f, "encap-sport %u", ntohs(sport));
fprintf(f, "encap-dport %u ", ntohs(dport));
fprintf(f, "encap-dport %u ", ntohs(dport));
if (flags & TUNNEL_ENCAP_FLAG_CSUM)
fputs("encap-csum ", f);
else
fputs("noencap-csum ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM)
fputs("encap-csum ", f);
else
fputs("noencap-csum ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
fputs("encap-csum6 ", f);
else
fputs("noencap-csum6 ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
fputs("encap-remcsum ", f);
else
fputs("noencap-remcsum ", f);
}
}
if (tb[IFLA_IPTUN_FWMARK] && rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]))
fprintf(f, "fwmark 0x%x ",
rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]));
if (tb[IFLA_IPTUN_FWMARK]) {
__u32 fwmark = rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]);
if (fwmark) {
snprintf(s2, sizeof(s2), "0x%x", fwmark);
print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
}
}
}
static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,

View File

@ -224,7 +224,7 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
remote = format_host(AF_INET, 4, &addr);
}
fprintf(f, "remote %s ", remote);
print_string(PRINT_ANY, "remote", "remote %s ", remote);
if (tb[IFLA_VTI_LOCAL]) {
unsigned int addr = rta_getattr_u32(tb[IFLA_VTI_LOCAL]);
@ -233,30 +233,36 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
local = format_host(AF_INET, 4, &addr);
}
fprintf(f, "local %s ", local);
print_string(PRINT_ANY, "local", "local %s ", local);
if (tb[IFLA_VTI_LINK] &&
(link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) {
const char *n = if_indextoname(link, s2);
if (n)
fprintf(f, "dev %s ", n);
print_string(PRINT_ANY, "link", "dev %s ", n);
else
fprintf(f, "dev %u ", link);
print_uint(PRINT_ANY, "link_index", "dev %u ", link);
}
if (tb[IFLA_VTI_IKEY] &&
(key = rta_getattr_u32(tb[IFLA_VTI_IKEY])))
fprintf(f, "ikey %#x ", ntohl(key));
print_0xhex(PRINT_ANY, "ikey", "ikey %#x ", ntohl(key));
if (tb[IFLA_VTI_OKEY] &&
(key = rta_getattr_u32(tb[IFLA_VTI_OKEY])))
fprintf(f, "okey %#x ", ntohl(key));
print_0xhex(PRINT_ANY, "okey", "okey %#x ", ntohl(key));
if (tb[IFLA_VTI_FWMARK] && rta_getattr_u32(tb[IFLA_VTI_FWMARK])) {
fprintf(f, "fwmark 0x%x ",
rta_getattr_u32(tb[IFLA_VTI_FWMARK]));
if (tb[IFLA_VTI_FWMARK]) {
__u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
if (fwmark) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "0x%x", fwmark);
print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
}
}
}

View File

@ -225,7 +225,7 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
remote = format_host(AF_INET6, 16, &daddr);
}
fprintf(f, "remote %s ", remote);
print_string(PRINT_ANY, "remote", "remote %s ", remote);
if (tb[IFLA_VTI_LOCAL]) {
memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr));
@ -233,29 +233,35 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
local = format_host(AF_INET6, 16, &saddr);
}
fprintf(f, "local %s ", local);
print_string(PRINT_ANY, "local", "local %s ", local);
if (tb[IFLA_VTI_LINK] && (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) {
const char *n = if_indextoname(link, s2);
if (n)
fprintf(f, "dev %s ", n);
print_string(PRINT_ANY, "link", "dev %s ", n);
else
fprintf(f, "dev %u ", link);
print_uint(PRINT_ANY, "link_index", "dev %u ", link);
}
if (tb[IFLA_VTI_IKEY]) {
inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2));
fprintf(f, "ikey %s ", s2);
print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
}
if (tb[IFLA_VTI_OKEY]) {
inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2));
fprintf(f, "okey %s ", s2);
print_string(PRINT_ANY, "okey", "okey %s ", s2);
}
if (tb[IFLA_VTI_FWMARK] && rta_getattr_u32(tb[IFLA_VTI_FWMARK])) {
fprintf(f, "fwmark 0x%x ", rta_getattr_u32(tb[IFLA_VTI_FWMARK]));
if (tb[IFLA_VTI_FWMARK]) {
__u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
if (fwmark) {
snprintf(s2, sizeof(s2), "0x%x", fwmark);
print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
}
}
}

View File

@ -1,16 +1,4 @@
include ../Config
ifeq ($(IP_CONFIG_SETNS),y)
CFLAGS += -DHAVE_SETNS
endif
ifeq ($(HAVE_ELF),y)
CFLAGS += -DHAVE_ELF
endif
ifeq ($(HAVE_MNL),y)
CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags)
endif
include ../config.mk
CFLAGS += -fPIC

View File

@ -89,6 +89,14 @@ void set_color_palette(void)
is_dark_bg = 1;
}
void check_if_color_enabled(void)
{
if (color_is_enabled) {
fprintf(stderr, "Option \"-json\" conflicts with \"-color\".\n");
exit(1);
}
}
int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...)
{
int ret = 0;
@ -96,13 +104,13 @@ int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...)
va_start(args, fmt);
if (!color_is_enabled) {
if (!color_is_enabled || attr == COLOR_NONE) {
ret = vfprintf(fp, fmt, args);
goto end;
}
ret += fprintf(fp, "%s",
color_codes[attr_colors[is_dark_bg ? attr + 7 : attr]]);
color_codes[attr_colors[is_dark_bg ? attr + 8 : attr]]);
ret += vfprintf(fp, fmt, args);
ret += fprintf(fp, "%s", color_codes[C_CLEAR]);

View File

@ -156,7 +156,7 @@ void jsonw_name(json_writer_t *self, const char *name)
putc(' ', self->out);
}
static void jsonw_printf(json_writer_t *self, const char *fmt, ...)
void jsonw_printf(json_writer_t *self, const char *fmt, ...)
{
va_list ap;
@ -199,23 +199,38 @@ void jsonw_bool(json_writer_t *self, bool val)
jsonw_printf(self, "%s", val ? "true" : "false");
}
#ifdef notused
void jsonw_null(json_writer_t *self)
{
jsonw_printf(self, "null");
}
void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num)
{
jsonw_printf(self, fmt, num);
}
#ifdef notused
void jsonw_float(json_writer_t *self, double num)
{
jsonw_printf(self, "%g", num);
}
#endif
void jsonw_hu(json_writer_t *self, unsigned short num)
{
jsonw_printf(self, "%hu", num);
}
void jsonw_uint(json_writer_t *self, uint64_t num)
{
jsonw_printf(self, "%"PRIu64, num);
}
void jsonw_lluint(json_writer_t *self, unsigned long long int num)
{
jsonw_printf(self, "%llu", num);
}
void jsonw_int(json_writer_t *self, int64_t num)
{
jsonw_printf(self, "%"PRId64, num);
@ -242,25 +257,46 @@ void jsonw_float_field(json_writer_t *self, const char *prop, double val)
}
#endif
void jsonw_float_field_fmt(json_writer_t *self,
const char *prop,
const char *fmt,
double val)
{
jsonw_name(self, prop);
jsonw_float_fmt(self, fmt, val);
}
void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num)
{
jsonw_name(self, prop);
jsonw_uint(self, num);
}
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
{
jsonw_name(self, prop);
jsonw_hu(self, num);
}
void jsonw_lluint_field(json_writer_t *self,
const char *prop,
unsigned long long int num)
{
jsonw_name(self, prop);
jsonw_lluint(self, num);
}
void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num)
{
jsonw_name(self, prop);
jsonw_int(self, num);
}
#ifdef notused
void jsonw_null_field(json_writer_t *self, const char *prop)
{
jsonw_name(self, prop);
jsonw_null(self);
}
#endif
#ifdef TEST
int main(int argc, char **argv)

View File

@ -120,6 +120,7 @@ ip-address \- protocol address management
.BR sit " |"
.BR gre " |"
.BR gretap " |"
.BR erspan " |"
.BR ip6gre " |"
.BR ip6gretap " |"
.BR vti " |"

View File

@ -202,6 +202,7 @@ ip-link \- network device configuration
.BR sit " |"
.BR gre " |"
.BR gretap " |"
.BR erspan " |"
.BR ip6gre " |"
.BR ip6gretap " |"
.BR vti " |"
@ -297,6 +298,9 @@ Link types:
.BR gretap
- Virtual L2 tunnel interface GRE over IPv4
.sp
.BR erspan
- Encapsulated Remote SPAN over GRE and IPv4
.sp
.BR ip6gre
- Virtual tunnel interface GRE over IPv6
.sp
@ -643,13 +647,13 @@ keyword.
.in -8
.TP
GRE, IPIP, SIT Type Support
GRE, IPIP, SIT, ERSPAN Type Support
For a link of types
.I GRE/IPIP/SIT
.I GRE/IPIP/SIT/ERSPAN
the following additional arguments are supported:
.BI "ip link add " DEVICE
.BR type " { " gre " | " ipip " | " sit " }"
.BR type " { " gre " | " ipip " | " sit " | " erspan " }"
.BI " remote " ADDR " local " ADDR
[
.BR encap " { " fou " | " gue " | " none " }"
@ -663,6 +667,8 @@ the following additional arguments are supported:
.I " [no]encap-remcsum "
] [
.I " mode " { ip6ip | ipip | mplsip | any } "
] [
.BR erspan " \fIIDX "
]
.in +8
@ -707,6 +713,13 @@ MPLS-Over-IPv4, "any" indicates IPv6, IPv4 or MPLS Over IPv4. Supported for
SIT where the default is "ip6ip" and IPIP where the default is "ipip".
IPv6-Over-IPv4 is not supported for IPIP.
.sp
.BR erspan " \fIIDX "
- specifies the ERSPAN index field.
.IR IDX
indicates a 20 bit index/port number associated with the ERSPAN
traffic's source port and direction.
.in -8
.TP

View File

@ -177,7 +177,7 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
.ti -8
.IR ENCAP " := [ "
.IR MPLS " | " IP " | " BPF " | " SEG6 " ] "
.IR MPLS " | " IP " | " BPF " | " SEG6 " | " SEG6LOCAL " ] "
.ti -8
.IR ENCAP_MPLS " := "
@ -214,12 +214,19 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
.IR ENCAP_SEG6 " := "
.B seg6
.BR mode " [ "
.BR encap " | " inline " ] "
.BR encap " | " inline " | " l2encap " ] "
.B segs
.IR SEGMENTS " [ "
.B hmac
.IR KEYID " ]"
.ti -8
.IR ENCAP_SEG6LOCAL " := "
.B seg6local
.BR action
.IR SEG6_ACTION " [ "
.IR SEG6_ACTION_PARAM " ] "
.ti -8
.IR ROUTE_GET_FLAGS " := "
.BR " [ "
@ -674,6 +681,9 @@ is a string specifying the supported encapsulation type. Namely:
.sp
.BI seg6
- encapsulation type IPv6 Segment Routing
.sp
.BI seg6local
- local SRv6 segment processing
.in -8
.I ENCAPHDR
@ -740,6 +750,10 @@ is a set of encapsulation attributes specific to the
- Encapsulate packet in an outer IPv6 header with SRH
.sp
.B mode l2encap
- Encapsulate ingress L2 frame within an outer IPv6 header and SRH
.sp
.I SEGMENTS
- List of comma-separated IPv6 addresses
.sp
@ -749,6 +763,56 @@ is a set of encapsulation attributes specific to the
.in -2
.sp
.B seg6local
.in +2
.IR SEG6_ACTION " [ "
.IR SEG6_ACTION_PARAM " ] "
- Operation to perform on matching packets.
The following actions are currently supported (\fB4.14+ only\fR).
.in +2
.B End
- Regular SRv6 processing as intermediate segment endpoint.
This action only accepts packets with a non-zero Segments Left
value. Other matching packets are dropped.
.B End.X nh6
.I NEXTHOP
- Regular SRv6 processing as intermediate segment endpoint.
Additionally, forward processed packets to given next-hop.
This action only accepts packets with a non-zero Segments Left
value. Other matching packets are dropped.
.B End.DX6 nh6
.I NEXTHOP
- Decapsulate inner IPv6 packet and forward it to the
specified next-hop. If the argument is set to ::, then
the next-hop is selected according to the local selection
rules. This action only accepts packets with either a zero Segments
Left value or no SRH at all, and an inner IPv6 packet. Other
matching packets are dropped.
.B End.B6 srh segs
.IR SEGMENTS " [ "
.B hmac
.IR KEYID " ] "
- Insert the specified SRH immediately after the IPv6 header,
update the DA with the first segment of the newly inserted SRH,
then forward the resulting packet. The original SRH is not
modified. This action only accepts packets with a non-zero
Segments Left value. Other matching packets are dropped.
.B End.B6.Encaps srh segs
.IR SEGMENTS " [ "
.B hmac
.IR KEYID " ] "
- Regular SRv6 processing as intermediate segment endpoint.
Additionally, encapsulate the matching packet within an outer IPv6 header
followed by the specified SRH. The destination address of the outer IPv6
header is set to the first segment of the new SRH. The source
address is set as described in \fBip-sr\fR(8).
.in -4
.in -8
.TP

View File

@ -1,4 +1,4 @@
.TH "actions in tc" 8 "4 Jul 2017" "iproute2" "Linux"
.TH "actions in tc" 8 "1 Aug 2017" "iproute2" "Linux"
.SH NAME
actions \- independently defined actions in tc
@ -33,6 +33,9 @@ actions \- independently defined actions in tc
.B actions
.BR ls " | " list
.I ACTNAMESPEC
[
.I ACTFILTER
]
.in +8
.I ACTSPEC
@ -60,6 +63,10 @@ ACTNAME
:=
.BI index " INDEX"
.I ACTFILTER
:=
.BI since " MSTIME"
.I COOKIESPEC
:=
.BI cookie " COOKIE"
@ -71,9 +78,8 @@ ACTNAME
.I ACTNAME
may be any valid action type: gact, mirred, bpf, connmark, csum, police, etc.
.I ACTPARAMS
are the action-specific parameters; see the man page for the specific action
type to be used for details.
.I MSTIME
Time since last update.
.I CONTROL
:= {
@ -132,6 +138,10 @@ List all the actions in the specified table. When combined with the
option for
.BR tc ","
display the statistics for all actions in the specified table.
When combined with the option
.B since
allows doing a millisecond time-filter since the last time an
action was used in the datapath.
.TP
.B flush
Delete all actions stored in the specified table.
@ -176,6 +186,19 @@ As such, it can be used as a correlating value for maintaining user state.
The value to be stored is completely arbitrary and does not require a specific
format. It is stored inside the action structure itself.
.TP
.BI since " MSTIME"
When dumping large number of actions, a millisecond time-filter can be
specified
.IR MSTIME "."
The
.I MSTIME
is a millisecond count since last time a packet hit the action.
As an example specifying "since 20000" implies to dump all actions
that have seen packets in the last 20 seconds. This option is useful
when the kernel has a large number of actions and you are only interested
in recently used actions.
.TP
.I CONTROL
The

View File

@ -82,7 +82,7 @@ is required only when
Optional six byte destination or source MAC address to encode.
.TP
.BI type " TYPE"
Optional 16-bit ethertype to encode.
Optional 16-bit ethertype to encode. If not specified value of 0xED3E will be used.
.TP
.BI CONTROL
Action to take following an encode/decode.

View File

@ -3,26 +3,12 @@ LNSTATOBJ=lnstat.o lnstat_util.o
TARGETS=ss nstat ifstat rtacct lnstat
include ../Config
include ../config.mk
ifeq ($(HAVE_BERKELEY_DB),y)
TARGETS += arpd
endif
ifeq ($(HAVE_SELINUX),y)
LDLIBS += $(shell $(PKG_CONFIG) --libs libselinux)
CFLAGS += $(shell $(PKG_CONFIG) --cflags libselinux) -DHAVE_SELINUX
endif
ifeq ($(IP_CONFIG_SETNS),y)
CFLAGS += -DHAVE_SETNS
endif
ifeq ($(HAVE_MNL),y)
CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags)
LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)
endif
all: $(TARGETS)
ss: $(SSOBJ)

View File

@ -1,4 +1,4 @@
include ../Config
include ../config.mk
DISTGEN = maketable normal pareto paretonormal
DISTDATA = normal.dist pareto.dist paretonormal.dist experimental.dist
@ -7,11 +7,6 @@ HOSTCC ?= $(CC)
CCOPTS = $(CBUILD_CFLAGS)
LDLIBS += -lm
ifeq ($(HAVE_MNL),y)
CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags)
LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)
endif
all: $(DISTGEN) $(DISTDATA)
$(DISTGEN):

View File

@ -1,13 +1,10 @@
include ../Config
include ../config.mk
ifeq ($(HAVE_MNL),y)
RDMA_OBJ = rdma.o utils.o dev.o link.o
TARGETS=rdma
CFLAGS += $(shell $(PKG_CONFIG) libmnl --cflags)
LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)
endif
all: $(TARGETS) $(LIBS)

View File

@ -2,11 +2,7 @@ TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o tc_monitor.o \
tc_exec.o m_police.o m_estimator.o m_action.o m_ematch.o \
emp_ematch.yacc.o emp_ematch.lex.o
include ../Config
ifeq ($(IP_CONFIG_SETNS),y)
CFLAGS += -DHAVE_SETNS
endif
include ../config.mk
SHARED_LIBS ?= y
@ -102,15 +98,6 @@ endif
TCOBJ += $(TCMODULES)
LDLIBS += -L. -lm
ifeq ($(HAVE_ELF),y)
CFLAGS += -DHAVE_ELF
LDLIBS += -lelf
endif
ifeq ($(HAVE_MNL),y)
CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags)
LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)
endif
ifeq ($(SHARED_LIBS),y)
LDLIBS += -ldl
LDFLAGS += -Wl,-export-dynamic

View File

@ -135,7 +135,7 @@ static int basic_print_opt(struct filter_util *qu, FILE *f,
}
if (tb[TCA_BASIC_ACT]) {
tc_print_action(f, tb[TCA_BASIC_ACT]);
tc_print_action(f, tb[TCA_BASIC_ACT], 0);
}
return 0;

View File

@ -239,7 +239,7 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f,
}
if (tb[TCA_BPF_ACT])
tc_print_action(f, tb[TCA_BPF_ACT]);
tc_print_action(f, tb[TCA_BPF_ACT], 0);
return 0;
}

View File

@ -102,7 +102,7 @@ static int cgroup_print_opt(struct filter_util *qu, FILE *f,
}
if (tb[TCA_CGROUP_ACT])
tc_print_action(f, tb[TCA_CGROUP_ACT]);
tc_print_action(f, tb[TCA_CGROUP_ACT], 0);
return 0;
}

View File

@ -347,7 +347,7 @@ static int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt,
tc_print_police(f, tb[TCA_FLOW_POLICE]);
if (tb[TCA_FLOW_ACT]) {
fprintf(f, "\n");
tc_print_action(f, tb[TCA_FLOW_ACT]);
tc_print_action(f, tb[TCA_FLOW_ACT], 0);
}
return 0;
}

View File

@ -1316,7 +1316,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
}
if (tb[TCA_FLOWER_ACT])
tc_print_action(f, tb[TCA_FLOWER_ACT]);
tc_print_action(f, tb[TCA_FLOWER_ACT], 0);
return 0;
}

View File

@ -160,7 +160,7 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u
if (tb[TCA_FW_ACT]) {
fprintf(f, "\n");
tc_print_action(f, tb[TCA_FW_ACT]);
tc_print_action(f, tb[TCA_FW_ACT], 0);
}
return 0;
}

View File

@ -145,7 +145,7 @@ static int matchall_print_opt(struct filter_util *qu, FILE *f,
}
if (tb[TCA_MATCHALL_ACT])
tc_print_action(f, tb[TCA_MATCHALL_ACT]);
tc_print_action(f, tb[TCA_MATCHALL_ACT], 0);
return 0;
}

View File

@ -168,7 +168,7 @@ static int route_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
if (tb[TCA_ROUTE4_POLICE])
tc_print_police(f, tb[TCA_ROUTE4_POLICE]);
if (tb[TCA_ROUTE4_ACT])
tc_print_action(f, tb[TCA_ROUTE4_ACT]);
tc_print_action(f, tb[TCA_ROUTE4_ACT], 0);
return 0;
}

View File

@ -402,7 +402,7 @@ static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, _
}
if (tb[TCA_RSVP_ACT]) {
tc_print_action(f, tb[TCA_RSVP_ACT]);
tc_print_action(f, tb[TCA_RSVP_ACT], 0);
}
if (tb[TCA_RSVP_POLICE])
tc_print_police(f, tb[TCA_RSVP_POLICE]);

View File

@ -173,7 +173,7 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f,
}
if (tb[TCA_TCINDEX_ACT]) {
fprintf(f, "\n");
tc_print_action(f, tb[TCA_TCINDEX_ACT]);
tc_print_action(f, tb[TCA_TCINDEX_ACT], 0);
}
return 0;
}

View File

@ -1337,7 +1337,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
}
if (tb[TCA_U32_ACT])
tc_print_action(f, tb[TCA_U32_ACT]);
tc_print_action(f, tb[TCA_U32_ACT], 0);
return 0;
}

View File

@ -346,21 +346,25 @@ tc_print_action_flush(FILE *f, const struct rtattr *arg)
}
int
tc_print_action(FILE *f, const struct rtattr *arg)
tc_print_action(FILE *f, const struct rtattr *arg, unsigned short tot_acts)
{
int i;
struct rtattr *tb[TCA_ACT_MAX_PRIO + 1];
if (arg == NULL)
return 0;
parse_rtattr_nested(tb, TCA_ACT_MAX_PRIO, arg);
if (!tot_acts)
tot_acts = TCA_ACT_MAX_PRIO;
struct rtattr *tb[tot_acts + 1];
parse_rtattr_nested(tb, tot_acts, arg);
if (tab_flush && NULL != tb[0] && NULL == tb[1])
return tc_print_action_flush(f, tb[0]);
for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
for (i = 0; i < tot_acts; i++) {
if (tb[i]) {
fprintf(f, "\n\taction order %d: ", i);
if (tc_print_one_action(f, tb[i]) < 0) {
@ -380,7 +384,8 @@ int print_action(const struct sockaddr_nl *who,
FILE *fp = (FILE *)arg;
struct tcamsg *t = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr *tb[TCAA_MAX+1];
__u32 *tot_acts = NULL;
struct rtattr *tb[TCA_ROOT_MAX+1];
len -= NLMSG_LENGTH(sizeof(*t));
@ -389,8 +394,12 @@ int print_action(const struct sockaddr_nl *who,
return -1;
}
parse_rtattr(tb, TCAA_MAX, TA_RTA(t), len);
parse_rtattr(tb, TCA_ROOT_MAX, TA_RTA(t), len);
if (tb[TCA_ROOT_COUNT])
tot_acts = RTA_DATA(tb[TCA_ROOT_COUNT]);
fprintf(fp, "total acts %d\n", tot_acts ? *tot_acts:0);
if (tb[TCA_ACT_TAB] == NULL) {
if (n->nlmsg_type != RTM_GETACTION)
fprintf(stderr, "print_action: NULL kind\n");
@ -414,7 +423,9 @@ int print_action(const struct sockaddr_nl *who,
fprintf(fp, "Replaced action ");
}
}
tc_print_action(fp, tb[TCA_ACT_TAB]);
tc_print_action(fp, tb[TCA_ACT_TAB], tot_acts ? *tot_acts:0);
return 0;
}
@ -427,7 +438,7 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p
char **argv = *argv_p;
int prio = 0;
int ret = 0;
__u32 i;
__u32 i = 0;
struct rtattr *tail;
struct rtattr *tail2;
struct nlmsghdr *ans = NULL;
@ -498,7 +509,8 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p
tail2 = NLMSG_TAIL(&req.n);
addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
if (i > 0)
addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
}
@ -561,12 +573,16 @@ static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***ar
return ret;
}
static int tc_act_list_or_flush(int argc, char **argv, int event)
static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event)
{
struct rtattr *tail, *tail2, *tail3, *tail4;
int ret = 0, prio = 0, msg_size = 0;
char k[16];
struct rtattr *tail, *tail2;
struct action_util *a = NULL;
struct nla_bitfield32 flag_select = { 0 };
char **argv = *argv_p;
__u32 msec_since = 0;
int argc = *argc_p;
char k[16];
struct {
struct nlmsghdr n;
struct tcamsg t;
@ -597,11 +613,31 @@ static int tc_act_list_or_flush(int argc, char **argv, int event)
}
strncpy(k, *argv, sizeof(k) - 1);
argc -= 1;
argv += 1;
if (argc && (strcmp(*argv, "since") == 0)) {
NEXT_ARG();
if (get_u32(&msec_since, *argv, 0))
invarg("dump time \"since\" is invalid", *argv);
}
addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
tail3 = NLMSG_TAIL(&req.n);
flag_select.value |= TCA_FLAG_LARGE_DUMP_ON;
flag_select.selector |= TCA_FLAG_LARGE_DUMP_ON;
addattr_l(&req.n, MAX_MSG, TCA_ROOT_FLAGS, &flag_select,
sizeof(struct nla_bitfield32));
tail3->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail3;
if (msec_since) {
tail4 = NLMSG_TAIL(&req.n);
addattr32(&req.n, MAX_MSG, TCA_ROOT_TIME_DELTA, msec_since);
tail4->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail4;
}
msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr));
if (event == RTM_GETACTION) {
@ -626,6 +662,8 @@ static int tc_act_list_or_flush(int argc, char **argv, int event)
bad_val:
*argc_p = argc;
*argv_p = argv;
return ret;
}
@ -655,13 +693,21 @@ int do_action(int argc, char **argv)
act_usage();
return -1;
}
return tc_act_list_or_flush(argc-2, argv+2, RTM_GETACTION);
argc -= 2;
argv += 2;
return tc_act_list_or_flush(&argc, &argv,
RTM_GETACTION);
} else if (matches(*argv, "flush") == 0) {
if (argc <= 2) {
act_usage();
return -1;
}
return tc_act_list_or_flush(argc-2, argv+2, RTM_DELACTION);
argc -= 2;
argv += 2;
return tc_act_list_or_flush(&argc, &argv,
RTM_DELACTION);
} else if (matches(*argv, "help") == 0) {
act_usage();
return -1;

View File

@ -63,6 +63,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
char dbuf[ETH_ALEN];
char sbuf[ETH_ALEN];
__u16 ife_type = 0;
int user_type = 0;
__u32 ife_prio = 0;
__u32 ife_prio_v = 0;
__u32 ife_mark = 0;
@ -124,7 +125,8 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
NEXT_ARG();
if (get_u16(&ife_type, *argv, 0))
invarg("ife type is invalid", *argv);
fprintf(stderr, "IFE type 0x%x\n", ife_type);
fprintf(stderr, "IFE type 0x%04X\n", ife_type);
user_type = 1;
} else if (matches(*argv, "dst") == 0) {
NEXT_ARG();
daddr = *argv;
@ -185,8 +187,10 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
if (daddr)
addattr_l(n, MAX_MSG, TCA_IFE_DMAC, dbuf, ETH_ALEN);
if (ife_type)
if (user_type)
addattr_l(n, MAX_MSG, TCA_IFE_TYPE, &ife_type, 2);
else
fprintf(stderr, "IFE type 0x%04X\n", ETH_P_IFE);
if (saddr)
addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN);

View File

@ -113,7 +113,7 @@ int act_parse_police(struct action_util *a, int *argc_p,
char ***argv_p, int tca_id, struct nlmsghdr *n);
int print_police(struct action_util *a, FILE *f, struct rtattr *tb);
int police_print_xstats(struct action_util *a, FILE *f, struct rtattr *tb);
int tc_print_action(FILE *f, const struct rtattr *tb);
int tc_print_action(FILE *f, const struct rtattr *tb, unsigned short tot_acts);
int tc_print_ipt(FILE *f, const struct rtattr *tb);
int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n);
void print_tm(FILE *f, const struct tcf_t *tm);

View File

@ -1,4 +1,5 @@
include ../Config
include ../config.mk
ifeq ($(HAVE_MNL),y)
TIPCOBJ=bearer.o \
@ -8,8 +9,6 @@ TIPCOBJ=bearer.o \
node.o socket.o \
peer.o tipc.o
include ../Config
TARGETS=tipc
CFLAGS += $(shell $(PKG_CONFIG) libmnl --cflags)
LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)