Merge branch 'master' into next

Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
David Ahern 2020-05-05 16:49:38 +00:00
commit 8c109059b5
26 changed files with 380 additions and 162 deletions

View File

@ -378,7 +378,7 @@ static int brlink_modify(int argc, char **argv)
state = strtol(*argv, &endptr, 10);
if (!(**argv != '\0' && *endptr == '\0')) {
for (state = 0; state < nstates; state++)
if (strcmp(port_states[state], *argv) == 0)
if (strcasecmp(port_states[state], *argv) == 0)
break;
if (state == nstates) {
fprintf(stderr,

View File

@ -22,6 +22,11 @@ enum vlan_show_subject {
VLAN_SHOW_TUNNELINFO,
};
#define VLAN_ID_LEN 9
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
static void usage(void)
{
fprintf(stderr,
@ -256,11 +261,11 @@ static int filter_vlan_check(__u16 vid, __u16 flags)
return 1;
}
static void open_vlan_port(int ifi_index, const char *fmt,
enum vlan_show_subject subject)
static void open_vlan_port(int ifi_index, enum vlan_show_subject subject)
{
open_json_object(NULL);
print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname", fmt,
print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname",
"%-" __stringify(IFNAMSIZ) "s ",
ll_index_to_name(ifi_index));
open_json_array(PRINT_JSON,
subject == VLAN_SHOW_VLAN ? "vlans": "tunnels");
@ -272,16 +277,18 @@ static void close_vlan_port(void)
close_json_object();
}
static void print_range(const char *name, __u32 start, __u32 id)
static unsigned int print_range(const char *name, __u32 start, __u32 id)
{
char end[64];
int width;
snprintf(end, sizeof(end), "%sEnd", name);
print_uint(PRINT_ANY, name, "\t %u", start);
width = print_uint(PRINT_ANY, name, "%u", start);
if (start != id)
print_uint(PRINT_ANY, end, "-%u", id);
width += print_uint(PRINT_ANY, end, "-%u", id);
return width;
}
static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex)
@ -290,14 +297,14 @@ static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex)
int rem = RTA_PAYLOAD(list);
__u16 last_vid_start = 0;
__u32 last_tunid_start = 0;
open_vlan_port(ifindex, "%s", VLAN_SHOW_TUNNELINFO);
bool opened = false;
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1];
__u32 tunnel_id = 0;
__u16 tunnel_vid = 0;
__u16 tunnel_flags = 0;
unsigned int width;
int vcheck_ret;
if (i->rta_type != IFLA_BRIDGE_VLAN_TUNNEL_INFO)
@ -331,13 +338,33 @@ static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex)
else if (vcheck_ret == 0)
continue;
if (!opened) {
open_vlan_port(ifindex, VLAN_SHOW_TUNNELINFO);
opened = true;
} else {
print_string(PRINT_FP, NULL,
"%-" __stringify(IFNAMSIZ) "s ", "");
}
open_json_object(NULL);
print_range("vlan", last_vid_start, tunnel_vid);
width = print_range("vlan", last_vid_start, tunnel_vid);
if (width <= VLAN_ID_LEN) {
char buf[VLAN_ID_LEN + 1];
snprintf(buf, sizeof(buf), "%-*s",
VLAN_ID_LEN - width, "");
print_string(PRINT_FP, NULL, "%s ", buf);
} else {
fprintf(stderr, "BUG: vlan range too wide, %u\n",
width);
}
print_range("tunid", last_tunid_start, tunnel_id);
close_json_object();
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
}
close_vlan_port();
if (opened)
close_vlan_port();
}
static int print_vlan(struct nlmsghdr *n, void *arg)
@ -366,16 +393,8 @@ static int print_vlan(struct nlmsghdr *n, void *arg)
return 0;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
/* if AF_SPEC isn't there, vlan table is not preset for this port */
if (!tb[IFLA_AF_SPEC]) {
if (!filter_vlan && !is_json_context()) {
color_fprintf(stdout, COLOR_IFNAME, "%s",
ll_index_to_name(ifm->ifi_index));
fprintf(stdout, "\tNone\n");
}
if (!tb[IFLA_AF_SPEC])
return 0;
}
switch (*subject) {
case VLAN_SHOW_VLAN:
@ -385,9 +404,7 @@ static int print_vlan(struct nlmsghdr *n, void *arg)
print_vlan_tunnel_info(tb[IFLA_AF_SPEC], ifm->ifi_index);
break;
}
print_string(PRINT_FP, NULL, "%s", _SL_);
fflush(stdout);
return 0;
}
@ -408,20 +425,23 @@ static void print_vlan_flags(__u16 flags)
static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
{
open_json_object(NULL);
print_hu(PRINT_ANY, "vid", " %hu", vstats->vid);
print_hu(PRINT_ANY, "vid", "%hu", vstats->vid);
print_vlan_flags(vstats->flags);
print_nl();
print_lluint(PRINT_ANY, "rx_bytes",
"\n RX: %llu bytes",
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
print_lluint(PRINT_ANY, "rx_bytes", "RX: %llu bytes",
vstats->rx_bytes);
print_lluint(PRINT_ANY, "rx_packets", " %llu packets\n",
vstats->rx_packets);
print_lluint(PRINT_ANY, "tx_bytes",
" TX: %llu bytes",
vstats->rx_packets);
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
print_lluint(PRINT_ANY, "tx_bytes", "TX: %llu bytes",
vstats->tx_bytes);
print_lluint(PRINT_ANY, "tx_packets", " %llu packets\n",
vstats->tx_packets);
vstats->tx_packets);
close_json_object();
}
@ -456,10 +476,11 @@ static void print_vlan_stats_attr(struct rtattr *attr, int ifindex)
/* found vlan stats, first time print the interface name */
if (!found_vlan) {
open_vlan_port(ifindex, "%-16s", VLAN_SHOW_VLAN);
open_vlan_port(ifindex, VLAN_SHOW_VLAN);
found_vlan = true;
} else {
print_string(PRINT_FP, NULL, "%-16s", "");
print_string(PRINT_FP, NULL,
"%-" __stringify(IFNAMSIZ) "s ", "");
}
print_one_vlan_stats(vstats);
}
@ -538,15 +559,17 @@ static int vlan_show(int argc, char **argv, int subject)
}
if (!is_json_context()) {
printf("port\tvlan ids");
printf("%-" __stringify(IFNAMSIZ) "s %-"
__stringify(VLAN_ID_LEN) "s", "port",
"vlan-id");
if (subject == VLAN_SHOW_TUNNELINFO)
printf("\ttunnel id");
printf(" tunnel-id");
printf("\n");
}
ret = rtnl_dump_filter(&rth, print_vlan, &subject);
if (ret < 0) {
fprintf(stderr, "Dump ternminated\n");
fprintf(stderr, "Dump terminated\n");
exit(1);
}
} else {
@ -559,7 +582,8 @@ static int vlan_show(int argc, char **argv, int subject)
}
if (!is_json_context())
printf("%-16s vlan id\n", "port");
printf("%-" __stringify(IFNAMSIZ) "s vlan-id\n",
"port");
if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
@ -588,8 +612,7 @@ void print_vlan_info(struct rtattr *tb, int ifindex)
struct rtattr *i, *list = tb;
int rem = RTA_PAYLOAD(list);
__u16 last_vid_start = 0;
open_vlan_port(ifindex, "%s", VLAN_SHOW_VLAN);
bool opened = false;
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
struct bridge_vlan_info *vinfo;
@ -608,14 +631,24 @@ void print_vlan_info(struct rtattr *tb, int ifindex)
else if (vcheck_ret == 0)
continue;
if (!opened) {
open_vlan_port(ifindex, VLAN_SHOW_VLAN);
opened = true;
} else {
print_string(PRINT_FP, NULL, "%-"
__stringify(IFNAMSIZ) "s ", "");
}
open_json_object(NULL);
print_range("vlan", last_vid_start, vinfo->vid);
print_vlan_flags(vinfo->flags);
close_json_object();
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
}
close_vlan_port();
if (opened)
close_vlan_port();
}
int do_vlan(int argc, char **argv)

View File

@ -6476,10 +6476,27 @@ static int cmd_region_read(struct dl *dl)
return err;
}
static int cmd_region_snapshot_new(struct dl *dl)
{
struct nlmsghdr *nlh;
int err;
nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_NEW,
NLM_F_REQUEST | NLM_F_ACK);
err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
DL_OPT_REGION_SNAPSHOT_ID, 0);
if (err)
return err;
return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
}
static void cmd_region_help(void)
{
pr_err("Usage: devlink region show [ DEV/REGION ]\n");
pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
pr_err(" devlink region new DEV/REGION snapshot SNAPSHOT_ID\n");
pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
}
@ -6503,6 +6520,9 @@ static int cmd_region(struct dl *dl)
} else if (dl_argv_match(dl, "read")) {
dl_arg_inc(dl);
return cmd_region_read(dl);
} else if (dl_argv_match(dl, "new")) {
dl_arg_inc(dl);
return cmd_region_snapshot_new(dl);
}
pr_err("Command \"%s\" not found\n", dl_argv(dl));
return -ENOENT;

View File

@ -44,20 +44,24 @@ void close_json_array(enum output_type type, const char *delim);
void print_nl(void);
#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); \
int 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) \
static inline int print_##type_name(enum output_type t, \
const char *key, \
const char *fmt, \
type value) \
{ \
print_color_##type_name(t, COLOR_NONE, key, fmt, value); \
return print_color_##type_name(t, COLOR_NONE, key, fmt, \
value); \
}
/* These functions return 0 if printing to a JSON context, number of
* characters printed otherwise (as calculated by printf(3)).
*/
_PRINT_FUNC(int, int)
_PRINT_FUNC(s64, int64_t)
_PRINT_FUNC(bool, bool)

View File

@ -1131,7 +1131,8 @@ static int xfrm_state_keep(struct nlmsghdr *n, void *arg)
if (!xfrm_state_filter_match(xsinfo))
return 0;
if (xsinfo->id.proto == IPPROTO_IPIP)
if (xsinfo->id.proto == IPPROTO_IPIP ||
xsinfo->id.proto == IPPROTO_IPV6)
return 0;
if (xb->offset > xb->size) {

View File

@ -123,20 +123,22 @@ void close_json_array(enum output_type type, const char *str)
*/
#define _PRINT_FUNC(type_name, type) \
__attribute__((format(printf, 4, 0))) \
void print_color_##type_name(enum output_type t, \
enum color_attr color, \
const char *key, \
const char *fmt, \
type value) \
int print_color_##type_name(enum output_type t, \
enum color_attr color, \
const char *key, \
const char *fmt, \
type value) \
{ \
int ret = 0; \
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(stdout, color, fmt, value); \
ret = color_fprintf(stdout, color, fmt, value); \
} \
return ret; \
}
_PRINT_FUNC(int, int);
_PRINT_FUNC(s64, int64_t);
@ -162,12 +164,14 @@ _PRINT_NAME_VALUE_FUNC(uint, unsigned int, u);
_PRINT_NAME_VALUE_FUNC(string, const char*, s);
#undef _PRINT_NAME_VALUE_FUNC
void print_color_string(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
const char *value)
int print_color_string(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
const char *value)
{
int ret = 0;
if (_IS_JSON_CONTEXT(type)) {
if (key && !value)
jsonw_name(_jw, key);
@ -176,8 +180,10 @@ void print_color_string(enum output_type type,
else
jsonw_string_field(_jw, key, value);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(stdout, color, fmt, value);
ret = color_fprintf(stdout, color, fmt, value);
}
return ret;
}
/*
@ -185,47 +191,58 @@ void print_color_string(enum output_type type,
* 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)
int print_color_bool(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
bool value)
{
int ret = 0;
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(stdout, color, fmt, value ? "true" : "false");
ret = color_fprintf(stdout, color, fmt,
value ? "true" : "false");
}
return ret;
}
/*
* 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 long long hex)
int print_color_0xhex(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
unsigned long long hex)
{
int ret = 0;
if (_IS_JSON_CONTEXT(type)) {
SPRINT_BUF(b1);
snprintf(b1, sizeof(b1), "%#llx", hex);
print_string(PRINT_JSON, key, NULL, b1);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(stdout, color, fmt, hex);
ret = color_fprintf(stdout, color, fmt, hex);
}
return ret;
}
void print_color_hex(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
unsigned int hex)
int print_color_hex(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
unsigned int hex)
{
int ret = 0;
if (_IS_JSON_CONTEXT(type)) {
SPRINT_BUF(b1);
@ -235,28 +252,34 @@ void print_color_hex(enum output_type type,
else
jsonw_string(_jw, b1);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(stdout, color, fmt, hex);
ret = color_fprintf(stdout, color, fmt, hex);
}
return ret;
}
/*
* 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)
int print_color_null(enum output_type type,
enum color_attr color,
const char *key,
const char *fmt,
const char *value)
{
int ret = 0;
if (_IS_JSON_CONTEXT(type)) {
if (key)
jsonw_null_field(_jw, key);
else
jsonw_null(_jw);
} else if (_IS_FP_CONTEXT(type)) {
color_fprintf(stdout, color, fmt, value);
ret = color_fprintf(stdout, color, fmt, value);
}
return ret;
}
/* Print line separator (if not in JSON mode) */

1
man/man8/.gitignore vendored
View File

@ -1,4 +1,5 @@
# these pages are built
ip-address.8
ip-link.8
ip-netns.8
ip-route.8

View File

@ -1,18 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
TARGETS = ip-address.8 ip-link.8 ip-route.8
TARGETS = ip-address.8 ip-link.8 ip-netns.8 ip-route.8
MAN8PAGES = $(TARGETS) $(filter-out $(TARGETS),$(wildcard *.8))
all: $(TARGETS)
ip-address.8: ip-address.8.in
sed "s|@SYSCONFDIR@|$(CONFDIR)|g" $< > $@
ip-link.8: ip-link.8.in
sed "s|@SYSCONFDIR@|$(CONFDIR)|g" $< > $@
ip-route.8: ip-route.8.in
sed "s|@SYSCONFDIR@|$(CONFDIR)|g" $< > $@
%: %.in
sed \
-e "s|@NETNS_ETC_DIR@|$(NETNS_ETC_DIR)|g" \
-e "s|@NETNS_RUN_DIR@|$(NETNS_RUN_DIR)|g" \
-e "s|@SYSCONFDIR@|$(CONFDIR)|g" \
$< > $@
distclean: clean

View File

@ -289,36 +289,49 @@ the STP path cost of the specified port.
.BI priority " PRIO "
the STP port priority. The priority value is an unsigned 8-bit quantity
(number between 0 and 255). This metric is used in the designated port an
droot port selectio algorithms.
droot port selection algorithms.
.TP
.BI state " STATE "
the operation state of the port. This is primarily used by user space STP/RSTP
implementation. One may enter a lowercased port state name, or one of the
the operation state of the port. Except state 0 (disable STP or BPDU filter feature),
this is primarily used by user space STP/RSTP
implementation. One may enter port state name (case insensitive), or one of the
numbers below. Negative inputs are ignored, and unrecognized names return an
error.
.B 0
- port is DISABLED. Make this port completely inactive.
- port is in STP
.B DISABLED
state. Make this port completely inactive for STP. This is also called
BPDU filter and could be used to disable STP on an untrusted port, like
a leaf virtual devices.
.sp
.B 1
- STP LISTENING state. Only valid if STP is enabled on the bridge. In this
- port is in STP
.B LISTENING
state. Only valid if STP is enabled on the bridge. In this
state the port listens for STP BPDUs and drops all other traffic frames.
.sp
.B 2
- STP LEARNING state. Only valid if STP is enabled on the bridge. In this
- port is in STP
.B LEARNING
state. Only valid if STP is enabled on the bridge. In this
state the port will accept traffic only for the purpose of updating MAC
address tables.
.sp
.B 3
- STP FORWARDING state. Port is fully active.
- port is in STP
.B FORWARDING
state. Port is fully active.
.sp
.B 4
- STP BLOCKING state. Only valid if STP is enabled on the bridge. This state
- port is in STP
.B BLOCKING
state. Only valid if STP is enabled on the bridge. This state
is used during the STP election process. In this state, port will only process
STP BPDUs.
.sp
@ -327,12 +340,25 @@ STP BPDUs.
.BR "guard on " or " guard off "
Controls whether STP BPDUs will be processed by the bridge port. By default,
the flag is turned off allowed BPDU processing. Turning this flag on will
cause the port to stop processing STP BPDUs.
disables
the bridge port if a STP BPDU packet is received.
If running Spanning Tree on bridge, hostile devices on the network
may send BPDU on a port and cause network failure. Setting
.B guard on
will detect and stop this by disabling the port.
The port will be restarted if link is brought down, or
removed and reattached. For example if guard is enable on
eth0:
.B ip link set dev eth0 down; ip link set dev eth0 up
.TP
.BR "hairpin on " or " hairpin off "
Controls whether traffic may be send back out of the port on which it was
received. By default, this flag is turned off and the bridge will not forward
received. This option is also called reflective relay mode, and is used to support
basic VEPA (Virtual Ethernet Port Aggregator) capabilities.
By default, this flag is turned off and the bridge will not forward
traffic back out of the receiving port.
.TP
@ -346,6 +372,11 @@ enabled on the bridge. By default the flag is off.
Controls whether a given port is allowed to become root port or not. Only used
when STP is enabled on the bridge. By default the flag is off.
This feature is also called root port guard.
If BPDU is received from a leaf (edge) port, it should not
be elected as root port. This could be used if using STP on a bridge and the downstream bridges are not fully
trusted; this prevents a hostile guest from rerouting traffic.
.TP
.BR "learning on " or " learning off "
Controls whether a given port will learn MAC addresses from received traffic or
@ -383,6 +414,32 @@ there is no MDB entry. By default this flag is on.
Controls whether a given port will replicate packets using unicast
instead of multicast. By default this flag is off.
This is done by copying the packet per host and
changing the multicast destination MAC to a unicast one accordingly.
.BR mcast_to_unicast
works on top of the multicast snooping feature of
the bridge. Which means unicast copies are only delivered to hosts which
are interested in it and signalized this via IGMP/MLD reports
previously.
This feature is intended for interface types which have a more reliable
and/or efficient way to deliver unicast packets than broadcast ones
(e.g. WiFi).
However, it should only be enabled on interfaces where no IGMPv2/MLDv1
report suppression takes place. IGMP/MLD report suppression issue is usually
overcome by the network daemon (supplicant) enabling AP isolation and
by that separating all STAs.
Delivery of STA-to-STA IP multicast is made possible again by
enabling and utilizing the bridge hairpin mode, which considers the
incoming port as a potential outgoing port, too (see
.B hairpin
option).
Hairpin mode is performed after multicast snooping, therefore leading to
only deliver reports to STAs running a multicast router.
.TP
.BR "neigh_suppress on " or " neigh_suppress off "
Controls whether neigh discovery (arp and nd) proxy and suppression is
@ -472,7 +529,7 @@ the interface to which this address is associated.
.B router
- the destination address is associated with a router.
Valid if the referenced device is a VXLAN type device and has
route shortcircuit enabled.
route short circuit enabled.
.sp
.B use

View File

@ -61,9 +61,9 @@ By default a process inherits its network namespace from its parent. Initially a
the processes share the same default network namespace from the init process.
By convention a named network namespace is an object at
.BR "/var/run/netns/" NAME
.BR "@NETNS_RUN_DIR@/" NAME
that can be opened. The file descriptor resulting from opening
.BR "/var/run/netns/" NAME
.BR "@NETNS_RUN_DIR@/" NAME
refers to the specified network namespace. Holding that file
descriptor open keeps the network namespace alive. The file
descriptor can be used with the
@ -72,13 +72,13 @@ system call to change the network namespace associated with a task.
For applications that are aware of network namespaces, the convention
is to look for global network configuration files first in
.BR "/etc/netns/" NAME "/"
.BR "@NETNS_ETC_DIR@/" NAME "/"
then in
.BR "/etc/".
For example, if you want a different version of
.BR /etc/resolv.conf
for a network namespace used to isolate your vpn you would name it
.BR /etc/netns/myvpn/resolv.conf.
.BR @NETNS_ETC_DIR@/myvpn/resolv.conf.
.B ip netns exec
automates handling of this configuration, file convention for network
@ -89,24 +89,24 @@ their traditional location in /etc.
.TP
.B ip netns list - show all of the named network namespaces
.sp
This command displays all of the network namespaces in /var/run/netns
This command displays all of the network namespaces in @NETNS_RUN_DIR@
.TP
.B ip netns add NAME - create a new named network namespace
.sp
If NAME is available in /var/run/netns/ this command creates a new
If NAME is available in @NETNS_RUN_DIR@ this command creates a new
network namespace and assigns NAME.
.TP
.B ip netns attach NAME PID - create a new named network namespace
.sp
If NAME is available in /var/run/netns/ this command attaches the network
If NAME is available in @NETNS_RUN_DIR@ this command attaches the network
namespace of the process PID to NAME as if it were created with ip netns.
.TP
.B ip [-all] netns delete [ NAME ] - delete the name of a network namespace(s)
.sp
If NAME is present in /var/run/netns it is umounted and the mount
If NAME is present in @NETNS_RUN_DIR@ it is umounted and the mount
point is removed. If this is the last user of the network namespace the
network namespace will be freed and all physical devices will be moved to the
default one, otherwise the network namespace persists until it has no more
@ -160,7 +160,7 @@ Once it is assigned, it's not possible to change it.
.TP
.B ip netns identify [PID] - Report network namespaces names for process
.sp
This command walks through /var/run/netns and finds all the network
This command walks through @NETNS_RUN_DIR@ and finds all the network
namespace names for network namespace of the specified process, if PID is
not specified then the current process will be used.
@ -201,7 +201,7 @@ and prints a line for each event it sees.
.sp
Network namespace ids are used to identify a peer network namespace. This
command displays nsids of the current network namespace and provides the
corresponding iproute2 netns name (from /var/run/netns) if any.
corresponding iproute2 netns name (from @NETNS_RUN_DIR@) if any.
The
.B target-nsid

View File

@ -177,7 +177,7 @@ static void print_hw_stats(const struct rtattr *arg, bool print_used)
print_string(PRINT_ANY, NULL, " %s", item->str);
}
close_json_array(PRINT_JSON, NULL);
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
}
static int parse_hw_stats(const char *str, struct nlmsghdr *n)
@ -291,7 +291,8 @@ done0:
invarg(cookie_err_m, *argv);
}
if (hex2mem(*argv, act_ck, slen / 2) < 0)
if (slen % 2 ||
hex2mem(*argv, act_ck, slen / 2) < 0)
invarg("cookie must be a hex string\n",
*argv);
@ -375,11 +376,11 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg)
if (show_stats && tb[TCA_ACT_STATS]) {
print_string(PRINT_FP, NULL, "\tAction statistics:", NULL);
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
open_json_object("stats");
print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL);
close_json_object();
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
}
if (tb[TCA_ACT_COOKIE]) {
int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]);
@ -388,7 +389,7 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg)
print_string(PRINT_ANY, "cookie", "\tcookie %s",
hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]),
strsz, b1, sizeof(b1)));
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
}
if (tb[TCA_ACT_FLAGS]) {
struct nla_bitfield32 *flags = RTA_DATA(tb[TCA_ACT_FLAGS]);
@ -397,7 +398,7 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg)
print_bool(PRINT_ANY, "no_percpu", "\tno_percpu",
flags->value &
TCA_ACT_FLAGS_NO_PERCPU_STATS);
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
}
if (tb[TCA_ACT_HW_STATS])
print_hw_stats(tb[TCA_ACT_HW_STATS], false);
@ -457,7 +458,7 @@ tc_print_action(FILE *f, const struct rtattr *arg, unsigned short tot_acts)
for (i = 0; i <= tot_acts; i++) {
if (tb[i]) {
open_json_object(NULL);
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "order",
"\taction order %u: ", i);
if (tc_print_one_action(f, tb[i]) < 0) {
@ -496,7 +497,7 @@ int print_action(struct nlmsghdr *n, void *arg)
open_json_object(NULL);
print_uint(PRINT_ANY, "total acts", "total acts %u",
tot_acts ? *tot_acts : 0);
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
close_json_object();
if (tb[TCA_ACT_TAB] == NULL) {
if (n->nlmsg_type != RTM_GETACTION)

View File

@ -125,7 +125,7 @@ static int print_connmark(struct action_util *au, FILE *f, struct rtattr *arg)
print_uint(PRINT_ANY, "zone", "zone %u", ci->zone);
print_action_control(f, " ", ci->action, "");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "index", "\t index %u", ci->index);
print_int(PRINT_ANY, "ref", " ref %d", ci->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", ci->bindcnt);
@ -137,7 +137,7 @@ static int print_connmark(struct action_util *au, FILE *f, struct rtattr *arg)
print_tm(f, tm);
}
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
return 0;
}

View File

@ -238,7 +238,7 @@ static int print_ctinfo(struct action_util *au, FILE *f, struct rtattr *arg)
print_hu(PRINT_ANY, "zone", "zone %u", zone);
print_action_control(f, " ", ci->action, "");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "index", "\t index %u", ci->index);
print_int(PRINT_ANY, "ref", " ref %d", ci->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", ci->bindcnt);
@ -256,7 +256,7 @@ static int print_ctinfo(struct action_util *au, FILE *f, struct rtattr *arg)
if (show_stats)
print_ctinfo_stats(f, tb);
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
return 0;
}

View File

@ -311,7 +311,7 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg)
sizeof(b2)));
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "index", "\t index %u", p->index);
print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
@ -324,7 +324,7 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg)
}
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
return 0;
}

View File

@ -265,7 +265,7 @@ static int print_mpls(struct action_util *au, FILE *f, struct rtattr *arg)
}
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
return 0;
}

View File

@ -172,7 +172,7 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg)
format_host_r(AF_INET, 4, &sel->new_addr, buf1, sizeof(buf1)));
print_action_control(f, " ", sel->action, "");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "index", "\t index %u", sel->index);
print_int(PRINT_ANY, "ref", " ref %d", sel->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", sel->bindcnt);
@ -185,7 +185,7 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg)
}
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
return 0;
}

View File

@ -167,7 +167,7 @@ static int print_sample(struct action_util *au, FILE *f, struct rtattr *arg)
print_action_control(f, " ", p->action, "");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "index", "\t index %u", p->index);
print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
@ -179,7 +179,7 @@ static int print_sample(struct action_util *au, FILE *f, struct rtattr *arg)
print_tm(f, tm);
}
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
return 0;
}

View File

@ -254,7 +254,7 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
print_action_control(f, " ", p->action, "");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "index", "\t index %u", p->index);
print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
@ -267,7 +267,7 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
}
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
return 0;
}

View File

@ -489,7 +489,7 @@ static void tunnel_key_print_ip_addr(FILE *f, const char *name,
else
return;
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
if (matches(name, "src_ip") == 0)
print_string(PRINT_ANY, "src_ip", "\tsrc_ip %s",
rt_addr_n2a_rta(family, attr));
@ -503,7 +503,7 @@ static void tunnel_key_print_key_id(FILE *f, const char *name,
{
if (!attr)
return;
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "key_id", "\tkey_id %u", rta_getattr_be32(attr));
}
@ -512,7 +512,7 @@ static void tunnel_key_print_dst_port(FILE *f, char *name,
{
if (!attr)
return;
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "dst_port", "\tdst_port %u",
rta_getattr_be16(attr));
}
@ -523,7 +523,7 @@ static void tunnel_key_print_flag(FILE *f, const char *name_on,
{
if (!attr)
return;
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_string(PRINT_ANY, "flag", "\t%s",
rta_getattr_u8(attr) ? name_on : name_off);
}
@ -655,11 +655,11 @@ static void tunnel_key_print_tos_ttl(FILE *f, char *name,
return;
if (matches(name, "tos") == 0 && rta_getattr_u8(attr) != 0) {
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "tos", "\ttos 0x%x",
rta_getattr_u8(attr));
} else if (matches(name, "ttl") == 0 && rta_getattr_u8(attr) != 0) {
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "ttl", "\tttl %u",
rta_getattr_u8(attr));
}
@ -712,7 +712,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
}
print_action_control(f, " ", parm->action, "");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
@ -725,7 +725,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
}
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
return 0;
}

View File

@ -97,6 +97,7 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
unsigned int interval = 0;
unsigned int diffserv = 0;
unsigned int memlimit = 0;
unsigned int fwmark = 0;
unsigned int target = 0;
__u64 bandwidth = 0;
int ack_filter = -1;
@ -107,7 +108,6 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
int autorate = -1;
int ingress = -1;
int overhead = 0;
int fwmark = -1;
int wash = -1;
int nat = -1;
int atm = -1;
@ -335,15 +335,12 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
return -1;
}
} else if (strcmp(*argv, "fwmark") == 0) {
unsigned int fwm;
NEXT_ARG();
if (get_u32(&fwm, *argv, 0)) {
if (get_u32(&fwmark, *argv, 0)) {
fprintf(stderr,
"Illegal value for \"fwmark\": \"%s\"\n", *argv);
return -1;
}
fwmark = fwm;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
@ -388,7 +385,7 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
if (memlimit)
addattr_l(n, 1024, TCA_CAKE_MEMORY, &memlimit,
sizeof(memlimit));
if (fwmark != -1)
if (fwmark)
addattr_l(n, 1024, TCA_CAKE_FWMARK, &fwmark,
sizeof(fwmark));
if (nat != -1)
@ -523,6 +520,10 @@ static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
RTA_PAYLOAD(tb[TCA_CAKE_RTT]) >= sizeof(__u32)) {
interval = rta_getattr_u32(tb[TCA_CAKE_RTT]);
}
if (tb[TCA_CAKE_MEMORY] &&
RTA_PAYLOAD(tb[TCA_CAKE_MEMORY]) >= sizeof(__u32)) {
memlimit = rta_getattr_u32(tb[TCA_CAKE_MEMORY]);
}
if (tb[TCA_CAKE_FWMARK] &&
RTA_PAYLOAD(tb[TCA_CAKE_FWMARK]) >= sizeof(__u32)) {
fwmark = rta_getattr_u32(tb[TCA_CAKE_FWMARK]);
@ -575,7 +576,7 @@ static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if (memlimit) {
print_uint(PRINT_JSON, "memlimit", NULL, memlimit);
print_string(PRINT_FP, NULL, "memlimit %s",
print_string(PRINT_FP, NULL, "memlimit %s ",
sprint_size(memlimit, b1));
}

View File

@ -57,6 +57,7 @@ static void explain(void)
" [ [no]pacing ] [ refill_delay TIME ]\n"
" [ low_rate_threshold RATE ]\n"
" [ orphan_mask MASK]\n"
" [ timer_slack TIME]\n"
" [ ce_threshold TIME ]\n");
}
@ -86,6 +87,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
unsigned int refill_delay;
unsigned int orphan_mask;
unsigned int ce_threshold;
unsigned int timer_slack;
bool set_plimit = false;
bool set_flow_plimit = false;
bool set_quantum = false;
@ -96,6 +98,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
bool set_orphan_mask = false;
bool set_low_rate_threshold = false;
bool set_ce_threshold = false;
bool set_timer_slack = false;
int pacing = -1;
struct rtattr *tail;
@ -146,6 +149,20 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
return -1;
}
set_ce_threshold = true;
} else if (strcmp(*argv, "timer_slack") == 0) {
__s64 t64;
NEXT_ARG();
if (get_time64(&t64, *argv)) {
fprintf(stderr, "Illegal \"timer_slack\"\n");
return -1;
}
timer_slack = t64;
if (timer_slack != t64) {
fprintf(stderr, "Illegal (out of range) \"timer_slack\"\n");
return -1;
}
set_timer_slack = true;
} else if (strcmp(*argv, "defrate") == 0) {
NEXT_ARG();
if (strchr(*argv, '%')) {
@ -240,6 +257,9 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
if (set_ce_threshold)
addattr_l(n, 1024, TCA_FQ_CE_THRESHOLD,
&ce_threshold, sizeof(ce_threshold));
if (set_timer_slack)
addattr_l(n, 1024, TCA_FQ_TIMER_SLACK,
&timer_slack, sizeof(timer_slack));
addattr_nest_end(n, tail);
return 0;
}
@ -254,6 +274,7 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
unsigned int refill_delay;
unsigned int orphan_mask;
unsigned int ce_threshold;
unsigned int timer_slack;
SPRINT_BUF(b1);
@ -355,6 +376,12 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
}
}
if (tb[TCA_FQ_TIMER_SLACK] &&
RTA_PAYLOAD(tb[TCA_FQ_TIMER_SLACK]) >= sizeof(__u32)) {
timer_slack = rta_getattr_u32(tb[TCA_FQ_TIMER_SLACK]);
fprintf(f, "timer_slack %s ", sprint_time64(timer_slack, b1));
}
return 0;
}

View File

@ -54,12 +54,14 @@ static void explain(void)
"[ memory_limit BYTES ]\n"
"[ target TIME ] [ interval TIME ]\n"
"[ quantum BYTES ] [ [no]ecn ]\n"
"[ ce_threshold TIME ]\n");
"[ ce_threshold TIME ]\n"
"[ drop_batch SIZE ]\n");
}
static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
struct nlmsghdr *n, const char *dev)
{
unsigned int drop_batch = 0;
unsigned int limit = 0;
unsigned int flows = 0;
unsigned int target = 0;
@ -89,6 +91,12 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
fprintf(stderr, "Illegal \"quantum\"\n");
return -1;
}
} else if (strcmp(*argv, "drop_batch") == 0) {
NEXT_ARG();
if (get_unsigned(&drop_batch, *argv, 0)) {
fprintf(stderr, "Illegal \"drop_batch\"\n");
return -1;
}
} else if (strcmp(*argv, "target") == 0) {
NEXT_ARG();
if (get_time(&target, *argv)) {
@ -147,6 +155,8 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
if (memory != ~0U)
addattr_l(n, 1024, TCA_FQ_CODEL_MEMORY_LIMIT,
&memory, sizeof(memory));
if (drop_batch)
addattr_l(n, 1024, TCA_FQ_CODEL_DROP_BATCH_SIZE, &drop_batch, sizeof(drop_batch));
addattr_nest_end(n, tail);
return 0;
@ -163,6 +173,7 @@ static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt
unsigned int quantum;
unsigned int ce_threshold;
unsigned int memory_limit;
unsigned int drop_batch;
SPRINT_BUF(b1);
@ -220,6 +231,12 @@ static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt
if (ecn)
print_bool(PRINT_ANY, "ecn", "ecn ", true);
}
if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE] &&
RTA_PAYLOAD(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]) >= sizeof(__u32)) {
drop_batch = rta_getattr_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]);
if (drop_batch)
print_uint(PRINT_ANY, "drop_batch", "drop_batch %u ", drop_batch);
}
return 0;
}
@ -264,7 +281,7 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f,
st->qdisc_stats.old_flows_len);
}
if (st->type == TCA_FQ_CODEL_XSTATS_CLASS) {
print_uint(PRINT_ANY, "deficit", " deficit %u",
print_int(PRINT_ANY, "deficit", " deficit %d",
st->class_stats.deficit);
print_uint(PRINT_ANY, "count", " count %u",
st->class_stats.count);

View File

@ -368,7 +368,7 @@ static int print_sched_list(FILE *f, struct rtattr *list)
open_json_array(PRINT_JSON, "schedule");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
for (item = RTA_DATA(list); RTA_OK(item, rem); item = RTA_NEXT(item, rem)) {
struct rtattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1];
@ -396,7 +396,7 @@ static int print_sched_list(FILE *f, struct rtattr *list)
print_uint(PRINT_ANY, "interval", " interval %u", interval);
close_json_object();
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
}
close_json_array(PRINT_ANY, "");
@ -454,7 +454,7 @@ static int taprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
print_uint(PRINT_ANY, NULL, " %u", qopt->prio_tc_map[i]);
close_json_array(PRINT_ANY, "");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
open_json_array(PRINT_ANY, "queues");
for (i = 0; i < qopt->num_tc; i++) {
@ -465,7 +465,7 @@ static int taprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
}
close_json_array(PRINT_ANY, "");
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
if (tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID])
clockid = rta_getattr_s32(tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]);

View File

@ -385,6 +385,11 @@ int get_size(unsigned int *size, const char *str)
}
*size = sz;
/* detect if an overflow happened */
if (*size != floor(sz))
return -1;
return 0;
}
@ -783,7 +788,7 @@ static void print_tcstats_basic_hw(struct rtattr **tbs, char *prefix)
sizeof(bs)));
if (bs.bytes >= bs_hw.bytes && bs.packets >= bs_hw.packets) {
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_string(PRINT_FP, NULL, "%s", prefix);
print_lluint(PRINT_ANY, "sw_bytes",
"Sent software %llu bytes",
@ -793,7 +798,7 @@ static void print_tcstats_basic_hw(struct rtattr **tbs, char *prefix)
}
}
print_string(PRINT_FP, NULL, "%s", _SL_);
print_nl();
print_string(PRINT_FP, NULL, "%s", prefix);
print_lluint(PRINT_ANY, "hw_bytes", "Sent hardware %llu bytes",
bs_hw.bytes);

View File

@ -0,0 +1,30 @@
#!/bin/sh
. lib/generic.sh
ts_log "[Testing vlan show]"
BR_DEV="$(rand_dev)"
VX0_DEV="$(rand_dev)"
VX1_DEV="$(rand_dev)"
ts_ip "$0" "Add $BR_DEV bridge interface" link add $BR_DEV type bridge
ts_ip "$0" "Add $VX0_DEV vxlan interface" \
link add $VX0_DEV type vxlan dstport 4789 external
ts_ip "$0" "Enslave $VX0_DEV under $BR_DEV" \
link set dev $VX0_DEV master $BR_DEV
ts_bridge "$0" "Delete default vlan from $VX0_DEV" \
vlan del dev $VX0_DEV vid 1
ts_ip "$0" "Add $VX1_DEV vxlan interface" \
link add $VX1_DEV type vxlan dstport 4790 external
ts_ip "$0" "Enslave $VX1_DEV under $BR_DEV" \
link set dev $VX1_DEV master $BR_DEV
# Test that bridge ports without vlans do not appear in the output
ts_bridge "$0" "Show vlan" vlan
test_on_not "$VX0_DEV"
# Test that bridge ports without tunnels do not appear in the output
ts_bridge "$0" "Show vlan tunnel info" vlan tunnelshow
test_lines_count 1 # header only

View File

@ -28,6 +28,6 @@ ts_bridge "$0" "Add tunnel with vni > 16k" \
ts_bridge "$0" "Show tunnel info" vlan tunnelshow dev $VX_DEV
test_on "1030\s+65556"
test_lines_count 5
test_lines_count 4
ts_bridge "$0" "Dump tunnel info" -j vlan tunnelshow dev $VX_DEV