aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <stephen@networkplumber.org>2020-01-29 05:44:53 -0800
committerStephen Hemminger <stephen@networkplumber.org>2020-01-29 05:44:53 -0800
commitd80d22d5fd63f82d056efafe1e42e6f5aef5223a (patch)
tree6cd5d2af04754dab185e67e0fd6aa98fa7e78f9f
parentd4df55404aec707bd55c9264c666ddb1bb05d7f1 (diff)
parenteae5f4b5c88eb60465d8b70c52efff57039d0024 (diff)
downloadiproute2-d80d22d5fd63f82d056efafe1e42e6f5aef5223a.tar.gz
Merge branch 'master' of git://git.kernel.org/pub/scm/network/iproute2/iproute2-next
Resolved conflict in tc/f_flower.c
-rw-r--r--include/libnetlink.h3
-rw-r--r--include/uapi/linux/bpf.h10
-rw-r--r--include/uapi/linux/btf.h3
-rw-r--r--include/uapi/linux/hdlc/ioctl.h9
-rw-r--r--include/uapi/linux/if.h1
-rw-r--r--include/uapi/linux/if_bonding.h10
-rw-r--r--include/uapi/linux/if_bridge.h39
-rw-r--r--include/uapi/linux/if_link.h8
-rw-r--r--include/uapi/linux/if_macsec.h11
-rw-r--r--include/uapi/linux/in.h2
-rw-r--r--include/uapi/linux/pkt_sched.h17
-rw-r--r--include/uapi/linux/rtnetlink.h11
-rw-r--r--include/uapi/linux/tcp.h5
-rw-r--r--include/uapi/linux/tipc_netlink.h2
-rw-r--r--include/uapi/linux/udp.h47
-rw-r--r--ip/ipaddress.c18
-rw-r--r--ip/iplink_bond_slave.c36
-rw-r--r--ip/iplink_bridge.c26
-rw-r--r--ip/iproute.c4
-rw-r--r--ip/iproute_lwtunnel.c9
-rw-r--r--ip/ipxfrm.c14
-rw-r--r--ip/xfrm_state.c2
-rw-r--r--man/man8/ip-xfrm.84
-rw-r--r--man/man8/tc-ets.8192
-rw-r--r--man/man8/tc.87
-rw-r--r--misc/ss.c19
-rw-r--r--tc/Makefile1
-rw-r--r--tc/f_flower.c5
-rw-r--r--tc/m_csum.c4
-rw-r--r--tc/m_ct.c5
-rw-r--r--tc/m_gact.c8
-rw-r--r--tc/m_mirred.c5
-rw-r--r--tc/m_mpls.c3
-rw-r--r--tc/m_pedit.c2
-rw-r--r--tc/m_simple.c2
-rw-r--r--tc/m_tunnel_key.c3
-rw-r--r--tc/m_vlan.c5
-rw-r--r--tc/m_xt.c2
-rw-r--r--tc/q_cake.c4
-rw-r--r--tc/q_ets.c342
-rw-r--r--tc/q_fq_codel.c3
-rw-r--r--tc/tc_class.c6
-rw-r--r--tc/tc_filter.c6
-rw-r--r--tc/tc_qdisc.c12
-rw-r--r--tc/tc_util.c2
45 files changed, 873 insertions, 56 deletions
diff --git a/include/libnetlink.h b/include/libnetlink.h
index 8ebdc6d3d..e27516f76 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -173,7 +173,8 @@ int rta_nest_end(struct rtattr *rta, struct rtattr *nest);
RTA_ALIGN((rta)->rta_len)))
#define parse_rtattr_nested(tb, max, rta) \
- (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)))
+ (parse_rtattr_flags((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta), \
+ NLA_F_NESTED))
#define parse_rtattr_one_nested(type, rta) \
(parse_rtattr_one(type, RTA_DATA(rta), RTA_PAYLOAD(rta)))
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 913d6df58..3e3f6e8d0 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -231,6 +231,11 @@ enum bpf_attach_type {
* When children program makes decision (like picking TCP CA or sock bind)
* parent program has a chance to override it.
*
+ * With BPF_F_ALLOW_MULTI a new program is added to the end of the list of
+ * programs for a cgroup. Though it's possible to replace an old program at
+ * any position by also specifying BPF_F_REPLACE flag and position itself in
+ * replace_bpf_fd attribute. Old program at this position will be released.
+ *
* A cgroup with MULTI or OVERRIDE flag allows any attach flags in sub-cgroups.
* A cgroup with NONE doesn't allow any programs in sub-cgroups.
* Ex1:
@@ -249,6 +254,7 @@ enum bpf_attach_type {
*/
#define BPF_F_ALLOW_OVERRIDE (1U << 0)
#define BPF_F_ALLOW_MULTI (1U << 1)
+#define BPF_F_REPLACE (1U << 2)
/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
* verifier will perform strict alignment checking as if the kernel
@@ -442,6 +448,10 @@ union bpf_attr {
__u32 attach_bpf_fd; /* eBPF program to attach */
__u32 attach_type;
__u32 attach_flags;
+ __u32 replace_bpf_fd; /* previously attached eBPF
+ * program to replace if
+ * BPF_F_REPLACE is used
+ */
};
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h
index d28dd89ae..7467223dc 100644
--- a/include/uapi/linux/btf.h
+++ b/include/uapi/linux/btf.h
@@ -142,7 +142,8 @@ struct btf_param {
enum {
BTF_VAR_STATIC = 0,
- BTF_VAR_GLOBAL_ALLOCATED,
+ BTF_VAR_GLOBAL_ALLOCATED = 1,
+ BTF_VAR_GLOBAL_EXTERN = 2,
};
/* BTF_KIND_VAR is followed by a single "struct btf_var" to describe
diff --git a/include/uapi/linux/hdlc/ioctl.h b/include/uapi/linux/hdlc/ioctl.h
index 0fe4238e8..b06341aca 100644
--- a/include/uapi/linux/hdlc/ioctl.h
+++ b/include/uapi/linux/hdlc/ioctl.h
@@ -79,6 +79,15 @@ typedef struct {
unsigned int timeout;
} cisco_proto;
+typedef struct {
+ unsigned short dce; /* 1 for DCE (network side) operation */
+ unsigned int modulo; /* modulo (8 = basic / 128 = extended) */
+ unsigned int window; /* frame window size */
+ unsigned int t1; /* timeout t1 */
+ unsigned int t2; /* timeout t2 */
+ unsigned int n2; /* frame retry counter */
+} x25_hdlc_proto;
+
/* PPP doesn't need any info now - supply length = 0 to ioctl */
#endif /* __ASSEMBLY__ */
diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h
index cf27ea4c4..074b14e38 100644
--- a/include/uapi/linux/if.h
+++ b/include/uapi/linux/if.h
@@ -211,6 +211,7 @@ struct if_settings {
fr_proto *fr;
fr_proto_pvc *fr_pvc;
fr_proto_pvc_info *fr_pvc_info;
+ x25_hdlc_proto *x25;
/* interface settings */
sync_serial_settings *sync;
diff --git a/include/uapi/linux/if_bonding.h b/include/uapi/linux/if_bonding.h
index 790585f0e..45f3750aa 100644
--- a/include/uapi/linux/if_bonding.h
+++ b/include/uapi/linux/if_bonding.h
@@ -95,6 +95,16 @@
#define BOND_XMIT_POLICY_ENCAP23 3 /* encapsulated layer 2+3 */
#define BOND_XMIT_POLICY_ENCAP34 4 /* encapsulated layer 3+4 */
+/* 802.3ad port state definitions (43.4.2.2 in the 802.3ad standard) */
+#define LACP_STATE_LACP_ACTIVITY 0x1
+#define LACP_STATE_LACP_TIMEOUT 0x2
+#define LACP_STATE_AGGREGATION 0x4
+#define LACP_STATE_SYNCHRONIZATION 0x8
+#define LACP_STATE_COLLECTING 0x10
+#define LACP_STATE_DISTRIBUTING 0x20
+#define LACP_STATE_DEFAULTED 0x40
+#define LACP_STATE_EXPIRED 0x80
+
typedef struct ifbond {
__s32 bond_mode;
__s32 num_slaves;
diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index 31fc51bde..18e8f3c4e 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -156,6 +156,44 @@ struct bridge_vlan_xstats {
__u32 pad2;
};
+struct bridge_stp_xstats {
+ __u64 transition_blk;
+ __u64 transition_fwd;
+ __u64 rx_bpdu;
+ __u64 tx_bpdu;
+ __u64 rx_tcn;
+ __u64 tx_tcn;
+};
+
+/* Bridge vlan RTM header */
+struct br_vlan_msg {
+ __u8 family;
+ __u8 reserved1;
+ __u16 reserved2;
+ __u32 ifindex;
+};
+
+/* Bridge vlan RTM attributes
+ * [BRIDGE_VLANDB_ENTRY] = {
+ * [BRIDGE_VLANDB_ENTRY_INFO]
+ * ...
+ * }
+ */
+enum {
+ BRIDGE_VLANDB_UNSPEC,
+ BRIDGE_VLANDB_ENTRY,
+ __BRIDGE_VLANDB_MAX,
+};
+#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1)
+
+enum {
+ BRIDGE_VLANDB_ENTRY_UNSPEC,
+ BRIDGE_VLANDB_ENTRY_INFO,
+ BRIDGE_VLANDB_ENTRY_RANGE,
+ __BRIDGE_VLANDB_ENTRY_MAX,
+};
+#define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
+
/* Bridge multicast database attributes
* [MDBA_MDB] = {
* [MDBA_MDB_ENTRY] = {
@@ -262,6 +300,7 @@ enum {
BRIDGE_XSTATS_VLAN,
BRIDGE_XSTATS_MCAST,
BRIDGE_XSTATS_PAD,
+ BRIDGE_XSTATS_STP,
__BRIDGE_XSTATS_MAX
};
#define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1)
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 1c49f4364..533abd2cf 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -169,6 +169,7 @@ enum {
IFLA_MAX_MTU,
IFLA_PROP_LIST,
IFLA_ALT_IFNAME, /* Alternative ifname */
+ IFLA_PERM_ADDRESS,
__IFLA_MAX
};
@@ -483,6 +484,13 @@ enum macsec_validation_type {
MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
};
+enum macsec_offload {
+ MACSEC_OFFLOAD_OFF = 0,
+ MACSEC_OFFLOAD_PHY = 1,
+ __MACSEC_OFFLOAD_END,
+ MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1,
+};
+
/* IPVLAN section */
enum {
IFLA_IPVLAN_UNSPEC,
diff --git a/include/uapi/linux/if_macsec.h b/include/uapi/linux/if_macsec.h
index 774399325..33c32051a 100644
--- a/include/uapi/linux/if_macsec.h
+++ b/include/uapi/linux/if_macsec.h
@@ -45,6 +45,7 @@ enum macsec_attrs {
MACSEC_ATTR_RXSC_LIST, /* dump, nested, macsec_rxsc_attrs for each RXSC */
MACSEC_ATTR_TXSC_STATS, /* dump, nested, macsec_txsc_stats_attr */
MACSEC_ATTR_SECY_STATS, /* dump, nested, macsec_secy_stats_attr */
+ MACSEC_ATTR_OFFLOAD, /* config, nested, macsec_offload_attrs */
__MACSEC_ATTR_END,
NUM_MACSEC_ATTR = __MACSEC_ATTR_END,
MACSEC_ATTR_MAX = __MACSEC_ATTR_END - 1,
@@ -97,6 +98,15 @@ enum macsec_sa_attrs {
MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1,
};
+enum macsec_offload_attrs {
+ MACSEC_OFFLOAD_ATTR_UNSPEC,
+ MACSEC_OFFLOAD_ATTR_TYPE, /* config/dump, u8 0..2 */
+ MACSEC_OFFLOAD_ATTR_PAD,
+ __MACSEC_OFFLOAD_ATTR_END,
+ NUM_MACSEC_OFFLOAD_ATTR = __MACSEC_OFFLOAD_ATTR_END,
+ MACSEC_OFFLOAD_ATTR_MAX = __MACSEC_OFFLOAD_ATTR_END - 1,
+};
+
enum macsec_nl_commands {
MACSEC_CMD_GET_TXSC,
MACSEC_CMD_ADD_RXSC,
@@ -108,6 +118,7 @@ enum macsec_nl_commands {
MACSEC_CMD_ADD_RXSA,
MACSEC_CMD_DEL_RXSA,
MACSEC_CMD_UPD_RXSA,
+ MACSEC_CMD_UPD_OFFLOAD,
};
/* u64 per-RXSC stats */
diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h
index ac079abcb..83a4c1874 100644
--- a/include/uapi/linux/in.h
+++ b/include/uapi/linux/in.h
@@ -76,6 +76,8 @@ enum {
#define IPPROTO_MPLS IPPROTO_MPLS
IPPROTO_RAW = 255, /* Raw IP packets */
#define IPPROTO_RAW IPPROTO_RAW
+ IPPROTO_MPTCP = 262, /* Multipath TCP connection */
+#define IPPROTO_MPTCP IPPROTO_MPTCP
IPPROTO_MAX
};
#endif
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 9f1a72876..bf5a5b1df 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -1187,4 +1187,21 @@ enum {
#define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1)
+/* ETS */
+
+#define TCQ_ETS_MAX_BANDS 16
+
+enum {
+ TCA_ETS_UNSPEC,
+ TCA_ETS_NBANDS, /* u8 */
+ TCA_ETS_NSTRICT, /* u8 */
+ TCA_ETS_QUANTA, /* nested TCA_ETS_QUANTA_BAND */
+ TCA_ETS_QUANTA_BAND, /* u32 */
+ TCA_ETS_PRIOMAP, /* nested TCA_ETS_PRIOMAP_BAND */
+ TCA_ETS_PRIOMAP_BAND, /* u8 */
+ __TCA_ETS_MAX,
+};
+
+#define TCA_ETS_MAX (__TCA_ETS_MAX - 1)
+
#endif
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 4b93791cd..9d802cd7f 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -171,6 +171,13 @@ enum {
RTM_GETLINKPROP,
#define RTM_GETLINKPROP RTM_GETLINKPROP
+ RTM_NEWVLAN = 112,
+#define RTM_NEWNVLAN RTM_NEWVLAN
+ RTM_DELVLAN,
+#define RTM_DELVLAN RTM_DELVLAN
+ RTM_GETVLAN,
+#define RTM_GETVLAN RTM_GETVLAN
+
__RTM_MAX,
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
};
@@ -309,6 +316,8 @@ enum rt_scope_t {
#define RTM_F_PREFIX 0x800 /* Prefix addresses */
#define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */
#define RTM_F_FIB_MATCH 0x2000 /* return full fib lookup match */
+#define RTM_F_OFFLOAD 0x4000 /* route is offloaded */
+#define RTM_F_TRAP 0x8000 /* route is trapping packets */
/* Reserved table identifiers */
@@ -719,6 +728,8 @@ enum rtnetlink_groups {
#define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R
RTNLGRP_NEXTHOP,
#define RTNLGRP_NEXTHOP RTNLGRP_NEXTHOP
+ RTNLGRP_BRVLAN,
+#define RTNLGRP_BRVLAN RTNLGRP_BRVLAN
__RTNLGRP_MAX
};
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
index 9415cb9fe..0a2c423e1 100644
--- a/include/uapi/linux/tcp.h
+++ b/include/uapi/linux/tcp.h
@@ -317,14 +317,15 @@ enum {
#define TCP_MD5SIG_MAXKEYLEN 80
/* tcp_md5sig extension flags for TCP_MD5SIG_EXT */
-#define TCP_MD5SIG_FLAG_PREFIX 1 /* address prefix length */
+#define TCP_MD5SIG_FLAG_PREFIX 0x1 /* address prefix length */
+#define TCP_MD5SIG_FLAG_IFINDEX 0x2 /* ifindex set */
struct tcp_md5sig {
struct __kernel_sockaddr_storage tcpm_addr; /* address associated */
__u8 tcpm_flags; /* extension flags */
__u8 tcpm_prefixlen; /* address prefix */
__u16 tcpm_keylen; /* key length */
- __u32 __tcpm_pad; /* zero */
+ int tcpm_ifindex; /* device index for scope */
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
};
diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h
index 6c2194ab7..dc0d23a50 100644
--- a/include/uapi/linux/tipc_netlink.h
+++ b/include/uapi/linux/tipc_netlink.h
@@ -65,6 +65,7 @@ enum {
TIPC_NL_UDP_GET_REMOTEIP,
TIPC_NL_KEY_SET,
TIPC_NL_KEY_FLUSH,
+ TIPC_NL_ADDR_LEGACY_GET,
__TIPC_NL_CMD_MAX,
TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
@@ -176,6 +177,7 @@ enum {
TIPC_NLA_NET_ADDR, /* u32 */
TIPC_NLA_NET_NODEID, /* u64 */
TIPC_NLA_NET_NODEID_W1, /* u64 */
+ TIPC_NLA_NET_ADDR_LEGACY, /* flag */
__TIPC_NLA_NET_MAX,
TIPC_NLA_NET_MAX = __TIPC_NLA_NET_MAX - 1
diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h
new file mode 100644
index 000000000..d0a7223a0
--- /dev/null
+++ b/include/uapi/linux/udp.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the UDP protocol.
+ *
+ * Version: @(#)udp.h 1.0.2 04/28/93
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * 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_UDP_H
+#define _LINUX_UDP_H
+
+#include <linux/types.h>
+
+struct udphdr {
+ __be16 source;
+ __be16 dest;
+ __be16 len;
+ __sum16 check;
+};
+
+/* UDP socket options */
+#define UDP_CORK 1 /* Never send partially complete segments */
+#define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */
+#define UDP_NO_CHECK6_TX 101 /* Disable sending checksum for UDP6X */
+#define UDP_NO_CHECK6_RX 102 /* Disable accpeting checksum for UDP6 */
+#define UDP_SEGMENT 103 /* Set GSO segmentation size */
+#define UDP_GRO 104 /* This socket can receive UDP GRO packets */
+
+/* UDP encapsulation types */
+#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
+#define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */
+#define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */
+#define UDP_ENCAP_GTP0 4 /* GSM TS 09.60 */
+#define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */
+#define UDP_ENCAP_RXRPC 6
+#define TCP_ENCAP_ESPINTCP 7 /* Yikes, this is really xfrm encap types. */
+
+#endif /* _LINUX_UDP_H */
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index b7e913240..80d27ce27 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1011,6 +1011,24 @@ int print_linkinfo(struct nlmsghdr *n, void *arg)
ifi->ifi_type,
b1, sizeof(b1)));
}
+ if (tb[IFLA_PERM_ADDRESS]) {
+ unsigned int len = RTA_PAYLOAD(tb[IFLA_PERM_ADDRESS]);
+
+ if (!tb[IFLA_ADDRESS] ||
+ RTA_PAYLOAD(tb[IFLA_ADDRESS]) != len ||
+ memcmp(RTA_DATA(tb[IFLA_PERM_ADDRESS]),
+ RTA_DATA(tb[IFLA_ADDRESS]), len)) {
+ print_string(PRINT_FP, NULL, " permaddr ", NULL);
+ print_color_string(PRINT_ANY,
+ COLOR_MAC,
+ "permaddr",
+ "%s",
+ ll_addr_n2a(RTA_DATA(tb[IFLA_PERM_ADDRESS]),
+ RTA_PAYLOAD(tb[IFLA_PERM_ADDRESS]),
+ ifi->ifi_type,
+ b1, sizeof(b1)));
+ }
+ }
}
if (tb[IFLA_LINK_NETNSID]) {
diff --git a/ip/iplink_bond_slave.c b/ip/iplink_bond_slave.c
index 4eaf72b86..d488aaab4 100644
--- a/ip/iplink_bond_slave.c
+++ b/ip/iplink_bond_slave.c
@@ -68,6 +68,26 @@ static void print_slave_mii_status(FILE *f, struct rtattr *tb)
slave_mii_status[status]);
}
+static void print_slave_oper_state(FILE *fp, const char *name, __u16 state)
+{
+ open_json_array(PRINT_ANY, name);
+ print_string(PRINT_FP, NULL, " <", NULL);
+#define _PF(s, str) if (state & LACP_STATE_##s) { \
+ state &= ~LACP_STATE_##s; \
+ print_string(PRINT_ANY, NULL, \
+ state ? "%s," : "%s", str); }
+ _PF(LACP_ACTIVITY, "active");
+ _PF(LACP_TIMEOUT, "short_timeout");
+ _PF(AGGREGATION, "aggregating");
+ _PF(SYNCHRONIZATION, "in_sync");
+ _PF(COLLECTING, "collecting");
+ _PF(DISTRIBUTING, "distributing");
+ _PF(DEFAULTED, "defaulted");
+ _PF(EXPIRED, "expired");
+#undef _PF
+ close_json_array(PRINT_ANY, "> ");
+}
+
static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
SPRINT_BUF(b1);
@@ -106,17 +126,25 @@ static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *t
"ad_aggregator_id %d ",
rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID]));
- if (tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE])
+ if (tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]) {
+ __u8 state = 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]));
+ state);
+ print_slave_oper_state(f, "ad_actor_oper_port_state_str", state);
+ }
+
+ if (tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]) {
+ __u16 state = rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]);
- if (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]));
+ state);
+ print_slave_oper_state(f, "ad_partner_oper_port_state_str", state);
+ }
}
static int bond_slave_parse_opt(struct link_util *lu, int argc, char **argv,
diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c
index 06f736d4d..bbd6f3a88 100644
--- a/ip/iplink_bridge.c
+++ b/ip/iplink_bridge.c
@@ -688,6 +688,7 @@ static void bridge_print_xstats_help(struct link_util *lu, FILE *f)
static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
{
struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
+ struct bridge_stp_xstats *sstats;
struct br_mcast_stats *mstats;
struct rtattr *i, *list;
const char *ifname = "";
@@ -807,6 +808,29 @@ static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
mstats->mld_parse_errors);
close_json_object();
break;
+ case BRIDGE_XSTATS_STP:
+ sstats = RTA_DATA(i);
+ open_json_object("stp");
+ print_string(PRINT_FP, NULL,
+ "%-16s STP BPDU: ", "");
+ print_u64(PRINT_ANY, "rx_bpdu", "RX: %llu ",
+ sstats->rx_bpdu);
+ print_u64(PRINT_ANY, "tx_bpdu", "TX: %llu\n",
+ sstats->tx_bpdu);
+ print_string(PRINT_FP, NULL,
+ "%-16s STP TCN: ", "");
+ print_u64(PRINT_ANY, "rx_tcn", "RX: %llu ",
+ sstats->rx_tcn);
+ print_u64(PRINT_ANY, "tx_tcn", "TX: %llu\n",
+ sstats->tx_tcn);
+ print_string(PRINT_FP, NULL,
+ "%-16s STP Transitions: ", "");
+ print_u64(PRINT_ANY, "transition_blk", "Blocked: %llu ",
+ sstats->transition_blk);
+ print_u64(PRINT_ANY, "transition_fwd", "Forwarding: %llu\n",
+ sstats->transition_fwd);
+ close_json_object();
+ break;
}
}
close_json_object();
@@ -843,6 +867,8 @@ int bridge_parse_xstats(struct link_util *lu, int argc, char **argv)
while (argc > 0) {
if (strcmp(*argv, "igmp") == 0 || strcmp(*argv, "mcast") == 0) {
xstats_print_attr = BRIDGE_XSTATS_MCAST;
+ } else if (strcmp(*argv, "stp") == 0) {
+ xstats_print_attr = BRIDGE_XSTATS_STP;
} else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
filter_index = ll_name_to_index(*argv);
diff --git a/ip/iproute.c b/ip/iproute.c
index 32bb52df2..93b805c90 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -368,6 +368,10 @@ void print_rt_flags(FILE *fp, unsigned int flags)
print_string(PRINT_ANY, NULL, "%s ", "linkdown");
if (flags & RTNH_F_UNRESOLVED)
print_string(PRINT_ANY, NULL, "%s ", "unresolved");
+ if (flags & RTM_F_OFFLOAD)
+ print_string(PRINT_ANY, NULL, "%s ", "rt_offload");
+ if (flags & RTM_F_TRAP)
+ print_string(PRINT_ANY, NULL, "%s ", "rt_trap");
close_json_array(PRINT_JSON, NULL);
}
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
index 60f34a32a..0d7d7149b 100644
--- a/ip/iproute_lwtunnel.c
+++ b/ip/iproute_lwtunnel.c
@@ -229,6 +229,8 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
struct rtattr *tb[SEG6_LOCAL_MAX + 1];
int action;
+ SPRINT_BUF(b1);
+
parse_rtattr_nested(tb, SEG6_LOCAL_MAX, encap);
if (!tb[SEG6_LOCAL_ACTION])
@@ -246,8 +248,9 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
}
if (tb[SEG6_LOCAL_TABLE])
- print_uint(PRINT_ANY, "table",
- "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
+ print_string(PRINT_ANY, "table", "table %s ",
+ rtnl_rttable_n2a(rta_getattr_u32(tb[SEG6_LOCAL_TABLE]),
+ b1, sizeof(b1)));
if (tb[SEG6_LOCAL_NH4]) {
print_string(PRINT_ANY, "nh4",
@@ -654,7 +657,7 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
NEXT_ARG();
if (table_ok++)
duparg2("table", *argv);
- get_u32(&table, *argv, 0);
+ rtnl_rttable_a2n(&table, *argv);
ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
} else if (strcmp(*argv, "nh4") == 0) {
NEXT_ARG();
diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c
index 32f560933..fec206abc 100644
--- a/ip/ipxfrm.c
+++ b/ip/ipxfrm.c
@@ -34,6 +34,7 @@
#include <netdb.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <linux/udp.h>
#include "utils.h"
#include "xfrm.h"
@@ -753,12 +754,15 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
fprintf(fp, "type ");
switch (e->encap_type) {
- case 1:
+ case UDP_ENCAP_ESPINUDP_NON_IKE:
fprintf(fp, "espinudp-nonike ");
break;
- case 2:
+ case UDP_ENCAP_ESPINUDP:
fprintf(fp, "espinudp ");
break;
+ case TCP_ENCAP_ESPINTCP:
+ fprintf(fp, "espintcp ");
+ break;
default:
fprintf(fp, "%u ", e->encap_type);
break;
@@ -1208,9 +1212,11 @@ int xfrm_encap_type_parse(__u16 *type, int *argcp, char ***argvp)
char **argv = *argvp;
if (strcmp(*argv, "espinudp-nonike") == 0)
- *type = 1;
+ *type = UDP_ENCAP_ESPINUDP_NON_IKE;
else if (strcmp(*argv, "espinudp") == 0)
- *type = 2;
+ *type = UDP_ENCAP_ESPINUDP;
+ else if (strcmp(*argv, "espintcp") == 0)
+ *type = TCP_ENCAP_ESPINTCP;
else
invarg("ENCAP-TYPE value is invalid", *argv);
diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
index b03ccc580..df2d50c38 100644
--- a/ip/xfrm_state.c
+++ b/ip/xfrm_state.c
@@ -130,7 +130,7 @@ static void usage(void)
"LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n"
"LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n"
" { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n"
- "ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n"
+ "ENCAP := { espinudp | espinudp-nonike | espintcp } SPORT DPORT OADDR\n"
"DIR := in | out\n");
exit(-1);
diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8
index cfce1e40b..f99f30bb4 100644
--- a/man/man8/ip-xfrm.8
+++ b/man/man8/ip-xfrm.8
@@ -207,7 +207,7 @@ ip-xfrm \- transform configuration
.ti -8
.IR ENCAP " :="
-.RB "{ " espinudp " | " espinudp-nonike " }"
+.RB "{ " espinudp " | " espinudp-nonike " | " espintcp " }"
.IR SPORT " " DPORT " " OADDR
.ti -8
@@ -548,7 +548,7 @@ sets limits in seconds, bytes, or numbers of packets.
.TP
.I ENCAP
encapsulates packets with protocol
-.BR espinudp " or " espinudp-nonike ","
+.BR espinudp ", " espinudp-nonike ", or " espintcp ","
.RI "using source port " SPORT ", destination port " DPORT
.RI ", and original address " OADDR "."
diff --git a/man/man8/tc-ets.8 b/man/man8/tc-ets.8
new file mode 100644
index 000000000..d3e68167a
--- /dev/null
+++ b/man/man8/tc-ets.8
@@ -0,0 +1,192 @@
+.TH TC 8 "December 2019" "iproute2" "Linux"
+.SH NAME
+ETS \- Enhanced Transmission Selection scheduler
+.SH SYNOPSIS
+.B tc qdisc ... ets [ bands
+number
+.B ] [ strict
+number
+.B ] [ quanta
+bytes bytes bytes...
+.B ] [ priomap
+band band band...
+.B ]
+
+.B tc class ... ets [ quantum
+bytes
+.B ]
+
+.SH DESCRIPTION
+
+The Enhanced Transmission Selection scheduler is a classful queuing
+discipline that merges functionality of PRIO and DRR qdiscs in one
+scheduler. ETS makes it easy to configure a set of strict and
+bandwidth-sharing bands to implement the transmission selection described
+in 802.1Qaz.
+
+On creation with 'tc qdisc add', a fixed number of bands is created. Each
+band is a class, although it is not possible to directly add and remove
+bands with 'tc class' commands. The number of bands to be created must
+instead be specified on the command line as the qdisc is added.
+
+The minor number of classid to use when referring to a band is the band
+number increased by one. Thus band 0 will have classid of major:1, band 1
+that of major:2, etc.
+
+ETS bands are of two types: some number may be in strict mode, the
+remaining ones are in bandwidth-sharing mode.
+
+.SH ALGORITHM
+When dequeuing, strict bands are tried first, if there are any. Band 0 is
+tried first. If it did not deliver a packet, band 1 is tried next, and so
+on until one of the bands delivers a packet, or the strict bands are
+exhausted.
+
+If no packet has been dequeued from any of the strict bands, if there are
+any bandwidth-sharing bands, the dequeuing proceeds according to the DRR
+algorithm. Each bandwidth-sharing band is assigned a deficit counter,
+initialized to quantum assigned by a
+.B quanta
+element. ETS maintains an (internal) ''active'' list of bandwidth-sharing
+bands whose qdiscs are non-empty. This list is used for dequeuing. A packet
+is dequeued from the band at the head of the list if the packet size is
+smaller or equal to the deficit counter. If the counter is too small, it is
+increased by
+.B quantum
+and the scheduler moves on to the next band in the active list.
+
+Only qdiscs that own their queue should be added below the
+bandwidth-sharing bands. Attaching to them non-work-conserving qdiscs like
+TBF does not make sense \-\- other qdiscs in the active list will be
+skipped until the dequeue operation succeeds. This limitation does not
+exist with the strict bands.
+
+.SH CLASSIFICATION
+The ETS qdisc allows three ways to decide which band to enqueue a packet
+to:
+
+- Packet priority can be directly set to a class handle, in which case that
+ is the queue where the packet will be put. For example, band number 2 of
+ a qdisc with handle of 11: will have classid 11:3. To mark a packet for
+ queuing to this band, the packet priority should be set to 0x110003.
+
+- A tc filter attached to the qdisc can put the packet to a band by using
+ the \fBflowid\fR keyword.
+
+- As a last resort, the ETS qdisc consults its priomap (see below), which
+ maps packets to bands based on packet priority.
+
+.SH PARAMETERS
+.TP
+strict
+The number of bands that should be created in strict mode. If not given,
+this value is 0.
+
+.TP
+quanta
+Each bandwidth-sharing band needs to know its quantum, which is the amount
+of bytes a band is allowed to dequeue before the scheduler moves to the
+next bandwidth-sharing band. The
+.B quanta
+argument lists quanta for the individual bandwidth-sharing bands.
+The minimum value of each quantum is 1. If
+.B quanta
+is not given, the default is no bandwidth-sharing bands, but note that when
+specifying a large number of
+.B bands,
+the extra ones are in bandwidth-sharing mode by default.
+
+.TP
+bands
+Number of bands given explicitly. This value has to be at least large
+enough to cover the strict bands specified through the
+.B strict
+keyword and bandwidth-sharing bands specified in
+.B quanta.
+If a larger value is given, any extra bands are in bandwidth-sharing mode,
+and their quanta are deduced from the interface MTU. If no value is given,
+as many bands are created as necessary to cover all bands implied by the
+.B strict
+and
+.B quanta
+keywords.
+
+.TP
+priomap
+The priomap maps the priority of a packet to a band. The argument is a list
+of numbers. The first number indicates which band the packets with priority
+0 should be put to, the second is for priority 1, and so on.
+
+There can be up to 16 numbers in the list. If there are fewer, the default
+band that traffic with one of the unmentioned priorities goes to is the
+last one.
+
+.SH EXAMPLE & USAGE
+
+.P
+Add a qdisc with 8 bandwidth-sharing bands, using the interface MTU as
+their quanta. Since all quanta are the same, this will lead to equal
+distribution of bandwidth between the bands, each will get about 12.5% of
+the link. The low 8 priorities go to individual bands in a reverse 1:1
+fashion (such that the highest priority goes to the first band).
+
+.P
+# tc qdisc add dev eth0 root handle 1: ets bands 8 priomap 7 6 5 4 3 2 1 0
+.br
+# tc qdisc show dev eth0
+.br
+qdisc ets 1: root refcnt 2 bands 8 quanta 1514 1514 1514 1514 1514 1514 1514 1514 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7
+
+.P
+Tweak the first band of the above qdisc to give it a quantum of 2650, which
+will give it about 20% of the link (and about 11.5% to the remaining
+bands):
+
+.P
+# tc class change dev eth0 classid 1:1 ets quantum 2650
+.br
+# tc qdisc show dev eth0
+.br
+qdisc ets 1: root refcnt 2 bands 8 quanta 2650 1514 1514 1514 1514 1514 1514 1514 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7
+
+.P
+Create a purely strict Qdisc with reverse 1:1 mapping between priorities
+and bands:
+
+.P
+# tc qdisc add dev eth0 root handle 1: ets strict 8 priomap 7 6 5 4 3 2 1 0
+.br
+# tc qdisc sh dev eth0
+.br
+qdisc ets 1: root refcnt 2 bands 8 strict 8 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7
+
+.P
+Add a Qdisc with 6 bands, 3 strict and 3 ETS with 35%-30%-25% weights:
+.P
+# tc qdisc add dev eth0 root handle 1: ets strict 3 quanta 3500 3000 2500 priomap 0 1 1 1 2 3 4 5
+.br
+# tc qdisc sh dev eth0
+.br
+qdisc ets 1: root refcnt 2 bands 6 strict 3 quanta 3500 3000 2500 priomap 0 1 1 1 2 3 4 5 5 5 5 5 5 5 5 5
+
+.P
+Create a Qdisc such that traffic with priorities 2, 3 and 4 are strictly
+prioritized over other traffic, and the rest goes into bandwidth-sharing
+classes with equal weights:
+.P
+# tc qdisc add dev eth0 root handle 1: ets bands 8 strict 3 priomap 3 4 0 1 2 5 6 7
+.br
+# tc qdisc sh dev eth0
+.br
+qdisc ets 1: root refcnt 2 bands 8 strict 3 quanta 1514 1514 1514 1514 1514 priomap 3 4 0 1 2 5 6 7 7 7 7 7 7 7 7 7
+
+.SH SEE ALSO
+.BR tc (8),
+.BR tc-prio (8),
+.BR tc-drr (8)
+
+.SH AUTHOR
+Parts of both this manual page and the code itself are taken from PRIO and
+DRR qdiscs.
+.br
+ETS qdisc itself was written by Petr Machata.
diff --git a/man/man8/tc.8 b/man/man8/tc.8
index d25aaddad..39976ad71 100644
--- a/man/man8/tc.8
+++ b/man/man8/tc.8
@@ -394,6 +394,12 @@ DSMARK
Classify packets based on TOS field, change TOS field of packets based on
classification.
.TP
+ETS
+The ETS qdisc is a queuing discipline that merges functionality of PRIO and DRR
+qdiscs in one scheduler. ETS makes it easy to configure a set of strict and
+bandwidth-sharing bands to implement the transmission selection described in
+802.1Qaz.
+.TP
HFSC
Hierarchical Fair Service Curve guarantees precise bandwidth and delay allocation for leaf classes and allocates excess bandwidth fairly. Unlike HTB, it makes use of packet dropping to achieve low delays which interactive sessions benefit from.
.TP
@@ -844,6 +850,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2.
.BR tc-codel (8),
.BR tc-drr (8),
.BR tc-ematch (8),
+.BR tc-ets (8),
.BR tc-flow (8),
.BR tc-flower (8),
.BR tc-fq (8),
diff --git a/misc/ss.c b/misc/ss.c
index 1e8bca5ae..3ef151fbf 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -1135,10 +1135,10 @@ static void buf_free_all(void)
buffer.chunks = 0;
}
-/* Get current screen width, default to 80 columns if TIOCGWINSZ fails */
+/* Get current screen width, returns -1 if TIOCGWINSZ fails */
static int render_screen_width(void)
{
- int width = 80;
+ int width = -1;
if (isatty(STDOUT_FILENO)) {
struct winsize w;
@@ -1159,9 +1159,15 @@ static int render_screen_width(void)
*/
static void render_calc_width(void)
{
- int screen_width = render_screen_width();
+ int screen_width, first, len = 0, linecols = 0;
struct column *c, *eol = columns - 1;
- int first, len = 0, linecols = 0;
+ bool compact_output = false;
+
+ screen_width = render_screen_width();
+ if (screen_width == -1) {
+ screen_width = INT_MAX;
+ compact_output = true;
+ }
/* First pass: set width for each column to measured content length */
for (first = 1, c = columns; c - columns < COL_MAX; c++) {
@@ -1183,6 +1189,11 @@ static void render_calc_width(void)
first = 0;
}
+ if (compact_output) {
+ /* Compact output, skip extending columns. */
+ return;
+ }
+
/* Second pass: find out newlines and distribute available spacing */
for (c = columns; c - columns < COL_MAX; c++) {
int pad, spacing, rem, last;
diff --git a/tc/Makefile b/tc/Makefile
index a378c403a..f06ba14b2 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -79,6 +79,7 @@ TCMODULES += q_cbs.o
TCMODULES += q_etf.o
TCMODULES += q_taprio.o
TCMODULES += q_plug.o
+TCMODULES += q_ets.o
TCSO :=
ifeq ($(TC_CONFIG_ATM),y)
diff --git a/tc/f_flower.c b/tc/f_flower.c
index 8f248db5b..9d59d71f9 100644
--- a/tc/f_flower.c
+++ b/tc/f_flower.c
@@ -2134,7 +2134,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_PRIO];
print_nl();
- print_uint(PRINT_ANY, "cvlan_prio", " cvlan_prio %d",
+ print_uint(PRINT_ANY, "cvlan_prio", " cvlan_prio %d",
rta_getattr_u8(attr));
}
@@ -2291,7 +2291,8 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
print_uint(PRINT_ANY, "in_hw_count",
" in_hw_count %u", count);
}
- } else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) {
+ }
+ else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) {
print_nl();
print_bool(PRINT_ANY, "not_in_hw", " not_in_hw", true);
}
diff --git a/tc/m_csum.c b/tc/m_csum.c
index 3e3dc251e..afbee9c8d 100644
--- a/tc/m_csum.c
+++ b/tc/m_csum.c
@@ -205,7 +205,7 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg)
uflag_4, uflag_5, uflag_6, uflag_7);
print_string(PRINT_ANY, "csum", "(%s) ", buf);
- print_action_control(f, "action ", sel->action, "\n");
+ print_action_control(f, "action ", sel->action, _SL_);
print_uint(PRINT_ANY, "index", "\tindex %u", sel->index);
print_int(PRINT_ANY, "ref", " ref %d", sel->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", sel->bindcnt);
@@ -217,7 +217,7 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg)
print_tm(f, tm);
}
}
- print_string(PRINT_FP, NULL, "%s", "\n");
+ print_nl();
return 0;
}
diff --git a/tc/m_ct.c b/tc/m_ct.c
index 45fa4a8c9..70d186e85 100644
--- a/tc/m_ct.c
+++ b/tc/m_ct.c
@@ -473,7 +473,8 @@ static int print_ct(struct action_util *au, FILE *f, struct rtattr *arg)
print_action_control(f, " ", p->action, "");
- print_uint(PRINT_ANY, "index", "\n\t index %u", p->index);
+ 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);
@@ -484,7 +485,7 @@ static int print_ct(struct action_util *au, FILE *f, struct rtattr *arg)
print_tm(f, tm);
}
}
- print_string(PRINT_FP, NULL, "%s", "\n ");
+ print_nl();
return 0;
}
diff --git a/tc/m_gact.c b/tc/m_gact.c
index b06e8ee95..33f326f82 100644
--- a/tc/m_gact.c
+++ b/tc/m_gact.c
@@ -193,13 +193,15 @@ print_gact(struct action_util *au, FILE *f, struct rtattr *arg)
pp = &pp_dummy;
}
open_json_object("prob");
- print_string(PRINT_ANY, "random_type", "\n\t random type %s",
+ print_nl();
+ print_string(PRINT_ANY, "random_type", "\t random type %s",
prob_n2a(pp->ptype));
print_action_control(f, " ", pp->paction, " ");
print_int(PRINT_ANY, "val", "val %d", pp->pval);
close_json_object();
#endif
- print_uint(PRINT_ANY, "index", "\n\t index %u", p->index);
+ 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);
if (show_stats) {
@@ -209,7 +211,7 @@ print_gact(struct action_util *au, FILE *f, struct rtattr *arg)
print_tm(f, tm);
}
}
- print_string(PRINT_FP, NULL, "%s", "\n");
+ print_nl();
return 0;
}
diff --git a/tc/m_mirred.c b/tc/m_mirred.c
index 132095237..d2bdf4074 100644
--- a/tc/m_mirred.c
+++ b/tc/m_mirred.c
@@ -307,7 +307,8 @@ print_mirred(struct action_util *au, FILE *f, struct rtattr *arg)
print_string(PRINT_ANY, "to_dev", " to device %s)", dev);
print_action_control(f, " ", p->action, "");
- print_uint(PRINT_ANY, "index", "\n \tindex %u", p->index);
+ print_nl();
+ print_uint(PRINT_ANY, "index", "\tindex %u", p->index);
print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
@@ -318,7 +319,7 @@ print_mirred(struct action_util *au, FILE *f, struct rtattr *arg)
print_tm(f, tm);
}
}
- print_string(PRINT_FP, NULL, "%s", "\n ");
+ print_nl();
return 0;
}
diff --git a/tc/m_mpls.c b/tc/m_mpls.c
index 4b1ec70e3..6f3a39f43 100644
--- a/tc/m_mpls.c
+++ b/tc/m_mpls.c
@@ -252,7 +252,8 @@ static int print_mpls(struct action_util *au, FILE *f, struct rtattr *arg)
}
print_action_control(f, " ", parm->action, "");
- print_uint(PRINT_ANY, "index", "\n\t index %u", parm->index);
+ 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);
diff --git a/tc/m_pedit.c b/tc/m_pedit.c
index 1cd2d162f..fccfd17ca 100644
--- a/tc/m_pedit.c
+++ b/tc/m_pedit.c
@@ -820,7 +820,7 @@ static int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
sel->nkeys);
}
- fprintf(f, "\n ");
+ print_nl();
free(keys_ex);
return 0;
diff --git a/tc/m_simple.c b/tc/m_simple.c
index 49e250472..70897d6b7 100644
--- a/tc/m_simple.c
+++ b/tc/m_simple.c
@@ -194,7 +194,7 @@ static int print_simple(struct action_util *au, FILE *f, struct rtattr *arg)
print_tm(f, tm);
}
}
- fprintf(f, "\n");
+ print_nl();
return 0;
}
diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
index 4e65e4447..8fde68913 100644
--- a/tc/m_tunnel_key.c
+++ b/tc/m_tunnel_key.c
@@ -420,7 +420,8 @@ static void tunnel_key_print_geneve_options(const char *name,
uint8_t type;
open_json_array(PRINT_JSON, name);
- print_string(PRINT_FP, name, "\n\t%s ", "geneve_opt");
+ print_nl();
+ print_string(PRINT_FP, name, "\t%s ", "geneve_opt");
while (rem) {
parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem);
diff --git a/tc/m_vlan.c b/tc/m_vlan.c
index 9c8071e9d..1096ba0fb 100644
--- a/tc/m_vlan.c
+++ b/tc/m_vlan.c
@@ -219,7 +219,8 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
}
print_action_control(f, " ", parm->action, "");
- print_uint(PRINT_ANY, "index", "\n\t index %u", parm->index);
+ 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);
@@ -231,7 +232,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
}
}
- print_string(PRINT_FP, NULL, "%s", "\n");
+ print_nl();
return 0;
}
diff --git a/tc/m_xt.c b/tc/m_xt.c
index bf0db2be9..487ba25ad 100644
--- a/tc/m_xt.c
+++ b/tc/m_xt.c
@@ -391,7 +391,7 @@ print_ipt(struct action_util *au, FILE *f, struct rtattr *arg)
print_tm(f, tm);
}
}
- fprintf(f, "\n");
+ print_nl();
xtables_free_opts(1);
diff --git a/tc/q_cake.c b/tc/q_cake.c
index 65ea07ef6..3c78b1767 100644
--- a/tc/q_cake.c
+++ b/tc/q_cake.c
@@ -766,7 +766,7 @@ static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
fprintf(f, " ");
for (i = 0; i < num_tins; i++)
fprintf(f, " Tin %u", i);
- fprintf(f, "\n");
+ fprintf(f, "%s", _SL_);
};
#define GET_TSTAT(i, attr) (tstat[i][TCA_CAKE_TIN_STATS_ ## attr])
@@ -775,7 +775,7 @@ static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
fprintf(f, name); \
for (i = 0; i < num_tins; i++) \
fprintf(f, " %12" fmts, val); \
- fprintf(f, "\n"); \
+ fprintf(f, "%s", _SL_); \
} \
} while (0)
diff --git a/tc/q_ets.c b/tc/q_ets.c
new file mode 100644
index 000000000..e7903d50e
--- /dev/null
+++ b/tc/q_ets.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+
+/*
+ * Enhanced Transmission Selection - 802.1Qaz-based Qdisc
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+ fprintf(stderr, "Usage: ... ets [bands NUMBER] [strict NUMBER] [quanta Q1 Q2...] [priomap P1 P2...]\n");
+}
+
+static void cexplain(void)
+{
+ fprintf(stderr, "Usage: ... ets [quantum Q1]\n");
+}
+
+static unsigned int parse_quantum(const char *arg)
+{
+ unsigned int quantum;
+
+ if (get_unsigned(&quantum, arg, 10)) {
+ fprintf(stderr, "Illegal \"quanta\" element\n");
+ return 0;
+ }
+ if (!quantum)
+ fprintf(stderr, "\"quanta\" must be > 0\n");
+ return quantum;
+}
+
+static int parse_nbands(const char *arg, __u8 *pnbands, const char *what)
+{
+ unsigned int tmp;
+
+ if (get_unsigned(&tmp, arg, 10)) {
+ fprintf(stderr, "Illegal \"%s\"\n", what);
+ return -1;
+ }
+ if (tmp > TCQ_ETS_MAX_BANDS) {
+ fprintf(stderr, "The number of \"%s\" must be <= %d\n",
+ what, TCQ_ETS_MAX_BANDS);
+ return -1;
+ }
+
+ *pnbands = tmp;
+ return 0;
+}
+
+static int ets_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+ struct nlmsghdr *n, const char *dev)
+{
+ __u8 nbands = 0;
+ __u8 nstrict = 0;
+ bool quanta_mode = false;
+ unsigned int nquanta = 0;
+ __u32 quanta[TCQ_ETS_MAX_BANDS];
+ bool priomap_mode = false;
+ unsigned int nprio = 0;
+ __u8 priomap[TC_PRIO_MAX + 1];
+ unsigned int tmp;
+ struct rtattr *tail, *nest;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "bands") == 0) {
+ if (nbands) {
+ fprintf(stderr, "Duplicate \"bands\"\n");
+ return -1;
+ }
+ NEXT_ARG();
+ if (parse_nbands(*argv, &nbands, "bands"))
+ return -1;
+ priomap_mode = quanta_mode = false;
+ } else if (strcmp(*argv, "strict") == 0) {
+ if (nstrict) {
+ fprintf(stderr, "Duplicate \"strict\"\n");
+ return -1;
+ }
+ NEXT_ARG();
+ if (parse_nbands(*argv, &nstrict, "strict"))
+ return -1;
+ priomap_mode = quanta_mode = false;
+ } else if (strcmp(*argv, "quanta") == 0) {
+ if (nquanta) {
+ fprintf(stderr, "Duplicate \"quanta\"\n");
+ return -1;
+ }
+ NEXT_ARG();
+ priomap_mode = false;
+ quanta_mode = true;
+ goto parse_quantum;
+ } else if (strcmp(*argv, "priomap") == 0) {
+ if (nprio) {
+ fprintf(stderr, "Duplicate \"priomap\"\n");
+ return -1;
+ }
+ NEXT_ARG();
+ priomap_mode = true;
+ quanta_mode = false;
+ goto parse_priomap;
+ } else if (strcmp(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else if (quanta_mode) {
+ unsigned int quantum;
+
+parse_quantum:
+ quantum = parse_quantum(*argv);
+ if (!quantum)
+ return -1;
+ quanta[nquanta++] = quantum;
+ } else if (priomap_mode) {
+ unsigned int band;
+
+parse_priomap:
+ if (get_unsigned(&band, *argv, 10)) {
+ fprintf(stderr, "Illegal \"priomap\" element\n");
+ return -1;
+ }
+ if (nprio > TC_PRIO_MAX) {
+ fprintf(stderr, "\"priomap\" index cannot be higher than %u\n", TC_PRIO_MAX);
+ return -1;
+ }
+ priomap[nprio++] = band;
+ } else {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ explain();
+ return -1;
+ }
+ argc--; argv++;
+ }
+
+ if (!nbands)
+ nbands = nquanta + nstrict;
+ if (!nbands) {
+ fprintf(stderr, "One of \"bands\", \"quanta\" or \"strict\" needs to be specified\n");
+ explain();
+ return -1;
+ }
+ if (nbands < 1) {
+ fprintf(stderr, "The number of \"bands\" must be >= 1\n");
+ explain();
+ return -1;
+ }
+ if (nstrict + nquanta > nbands) {
+ fprintf(stderr, "Not enough total bands to cover all the strict bands and quanta\n");
+ explain();
+ return -1;
+ }
+ for (tmp = 0; tmp < nprio; tmp++) {
+ if (priomap[tmp] >= nbands) {
+ fprintf(stderr, "\"priomap\" element is out of bounds\n");
+ return -1;
+ }
+ }
+
+ tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED);
+ addattr_l(n, 1024, TCA_ETS_NBANDS, &nbands, sizeof(nbands));
+ if (nstrict)
+ addattr_l(n, 1024, TCA_ETS_NSTRICT, &nstrict, sizeof(nstrict));
+ if (nquanta) {
+ nest = addattr_nest(n, 1024, TCA_ETS_QUANTA | NLA_F_NESTED);
+ for (tmp = 0; tmp < nquanta; tmp++)
+ addattr_l(n, 1024, TCA_ETS_QUANTA_BAND,
+ &quanta[tmp], sizeof(quanta[0]));
+ addattr_nest_end(n, nest);
+ }
+ if (nprio) {
+ nest = addattr_nest(n, 1024, TCA_ETS_PRIOMAP | NLA_F_NESTED);
+ for (tmp = 0; tmp < nprio; tmp++)
+ addattr_l(n, 1024, TCA_ETS_PRIOMAP_BAND,
+ &priomap[tmp], sizeof(priomap[0]));
+ addattr_nest_end(n, nest);
+ }
+ addattr_nest_end(n, tail);
+
+ return 0;
+}
+
+static int ets_parse_copt(struct qdisc_util *qu, int argc, char **argv,
+ struct nlmsghdr *n, const char *dev)
+{
+ unsigned int quantum = 0;
+ struct rtattr *tail;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "quantum") == 0) {
+ if (quantum) {
+ fprintf(stderr, "Duplicate \"quantum\"\n");
+ return -1;
+ }
+ NEXT_ARG();
+ quantum = parse_quantum(*argv);
+ if (!quantum)
+ return -1;
+ } else if (strcmp(*argv, "help") == 0) {
+ cexplain();
+ return -1;
+ } else {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ cexplain();
+ return -1;
+ }
+ argc--; argv++;
+ }
+
+ tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED);
+ if (quantum)
+ addattr_l(n, 1024, TCA_ETS_QUANTA_BAND, &quantum,
+ sizeof(quantum));
+ addattr_nest_end(n, tail);
+
+ return 0;
+}
+
+static int ets_print_opt_quanta(struct rtattr *opt)
+{
+ int len = RTA_PAYLOAD(opt);
+ unsigned int offset;
+
+ open_json_array(PRINT_ANY, "quanta");
+ for (offset = 0; offset < len; ) {
+ struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL};
+ struct rtattr *attr;
+ __u32 quantum;
+
+ attr = RTA_DATA(opt) + offset;
+ parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset);
+ offset += RTA_LENGTH(RTA_PAYLOAD(attr));
+
+ if (!tb[TCA_ETS_QUANTA_BAND]) {
+ fprintf(stderr, "No ETS band quantum\n");
+ return -1;
+ }
+
+ quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]);
+ print_uint(PRINT_ANY, NULL, " %u", quantum);
+
+ }
+ close_json_array(PRINT_ANY, " ");
+
+ return 0;
+}
+
+static int ets_print_opt_priomap(struct rtattr *opt)
+{
+ int len = RTA_PAYLOAD(opt);
+ unsigned int offset;
+
+ open_json_array(PRINT_ANY, "priomap");
+ for (offset = 0; offset < len; ) {
+ struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL};
+ struct rtattr *attr;
+ __u8 band;
+
+ attr = RTA_DATA(opt) + offset;
+ parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset);
+ offset += RTA_LENGTH(RTA_PAYLOAD(attr)) + 3 /* padding */;
+
+ if (!tb[TCA_ETS_PRIOMAP_BAND]) {
+ fprintf(stderr, "No ETS priomap band\n");
+ return -1;
+ }
+
+ band = rta_getattr_u8(tb[TCA_ETS_PRIOMAP_BAND]);
+ print_uint(PRINT_ANY, NULL, " %u", band);
+
+ }
+ close_json_array(PRINT_ANY, " ");
+
+ return 0;
+}
+
+static int ets_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+ struct rtattr *tb[TCA_ETS_MAX + 1];
+ __u8 nbands;
+ __u8 nstrict;
+ int err;
+
+ if (opt == NULL)
+ return 0;
+
+ parse_rtattr_nested(tb, TCA_ETS_MAX, opt);
+
+ if (!tb[TCA_ETS_NBANDS] || !tb[TCA_ETS_PRIOMAP]) {
+ fprintf(stderr, "Incomplete ETS options\n");
+ return -1;
+ }
+
+ nbands = rta_getattr_u8(tb[TCA_ETS_NBANDS]);
+ print_uint(PRINT_ANY, "bands", "bands %u ", nbands);
+
+ if (tb[TCA_ETS_NSTRICT]) {
+ nstrict = rta_getattr_u8(tb[TCA_ETS_NSTRICT]);
+ print_uint(PRINT_ANY, "strict", "strict %u ", nstrict);
+ }
+
+ if (tb[TCA_ETS_QUANTA]) {
+ err = ets_print_opt_quanta(tb[TCA_ETS_QUANTA]);
+ if (err)
+ return err;
+ }
+
+ return ets_print_opt_priomap(tb[TCA_ETS_PRIOMAP]);
+}
+
+static int ets_print_copt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+ struct rtattr *tb[TCA_ETS_MAX + 1];
+ __u32 quantum;
+
+ if (opt == NULL)
+ return 0;
+
+ parse_rtattr_nested(tb, TCA_ETS_MAX, opt);
+
+ if (tb[TCA_ETS_QUANTA_BAND]) {
+ quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]);
+ print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum);
+ }
+
+ return 0;
+}
+
+struct qdisc_util ets_qdisc_util = {
+ .id = "ets",
+ .parse_qopt = ets_parse_opt,
+ .parse_copt = ets_parse_copt,
+ .print_qopt = ets_print_opt,
+ .print_copt = ets_print_copt,
+};
diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c
index d002940da..efed4d289 100644
--- a/tc/q_fq_codel.c
+++ b/tc/q_fq_codel.c
@@ -257,7 +257,8 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f,
if (st->qdisc_stats.drop_overmemory)
print_uint(PRINT_ANY, "drop_overmemory", " drop_overmemory %u",
st->qdisc_stats.drop_overmemory);
- print_uint(PRINT_ANY, "new_flows_len", "\n new_flows_len %u",
+ print_nl();
+ print_uint(PRINT_ANY, "new_flows_len", " new_flows_len %u",
st->qdisc_stats.new_flows_len);
print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u",
st->qdisc_stats.old_flows_len);
diff --git a/tc/tc_class.c b/tc/tc_class.c
index c7e3cfdf6..39bea9712 100644
--- a/tc/tc_class.c
+++ b/tc/tc_class.c
@@ -246,8 +246,8 @@ static void graph_cls_show(FILE *fp, char *buf, struct hlist_head *root_list,
"+---(%s)", cls_id_str);
strcat(buf, str);
- parse_rtattr(tb, TCA_MAX, (struct rtattr *)cls->data,
- cls->data_len);
+ parse_rtattr_flags(tb, TCA_MAX, (struct rtattr *)cls->data,
+ cls->data_len, NLA_F_NESTED);
if (tb[TCA_KIND] == NULL) {
strcat(buf, " [unknown qdisc kind] ");
@@ -327,7 +327,7 @@ int print_class(struct nlmsghdr *n, void *arg)
if (filter_classid && t->tcm_handle != filter_classid)
return 0;
- parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);
+ parse_rtattr_flags(tb, TCA_MAX, TCA_RTA(t), len, NLA_F_NESTED);
if (tb[TCA_KIND] == NULL) {
fprintf(stderr, "print_class: NULL kind\n");
diff --git a/tc/tc_filter.c b/tc/tc_filter.c
index f7d2e4a66..c591a19f3 100644
--- a/tc/tc_filter.c
+++ b/tc/tc_filter.c
@@ -267,7 +267,7 @@ int print_filter(struct nlmsghdr *n, void *arg)
return -1;
}
- parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);
+ parse_rtattr_flags(tb, TCA_MAX, TCA_RTA(t), len, NLA_F_NESTED);
if (tb[TCA_KIND] == NULL && (n->nlmsg_type == RTM_NEWTFILTER ||
n->nlmsg_type == RTM_GETTFILTER ||
@@ -364,11 +364,11 @@ int print_filter(struct nlmsghdr *n, void *arg)
close_json_object();
}
}
- print_string(PRINT_FP, NULL, "\n", NULL);
+ print_nl();
if (show_stats && (tb[TCA_STATS] || tb[TCA_STATS2])) {
print_tcstats_attr(fp, tb, " ", NULL);
- print_string(PRINT_FP, NULL, "\n", NULL);
+ print_nl();
}
close_json_object();
diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c
index 17e399830..181fe2f04 100644
--- a/tc/tc_qdisc.c
+++ b/tc/tc_qdisc.c
@@ -235,7 +235,7 @@ int print_qdisc(struct nlmsghdr *n, void *arg)
if (filter_ifindex && filter_ifindex != t->tcm_ifindex)
return 0;
- parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);
+ parse_rtattr_flags(tb, TCA_MAX, TCA_RTA(t), len, NLA_F_NESTED);
if (tb[TCA_KIND] == NULL) {
fprintf(stderr, "print_qdisc: NULL kind\n");
@@ -317,11 +317,11 @@ int print_qdisc(struct nlmsghdr *n, void *arg)
}
close_json_object();
- print_string(PRINT_FP, NULL, "\n", NULL);
+ print_nl();
if (show_details && tb[TCA_STAB]) {
print_size_table(fp, " ", tb[TCA_STAB]);
- print_string(PRINT_FP, NULL, "\n", NULL);
+ print_nl();
}
if (show_stats) {
@@ -329,12 +329,12 @@ int print_qdisc(struct nlmsghdr *n, void *arg)
if (tb[TCA_STATS] || tb[TCA_STATS2] || tb[TCA_XSTATS]) {
print_tcstats_attr(fp, tb, " ", &xstats);
- print_string(PRINT_FP, NULL, "\n", NULL);
+ print_nl();
}
if (q && xstats && q->print_xstats) {
q->print_xstats(q, fp, xstats);
- print_string(PRINT_FP, NULL, "\n", NULL);
+ print_nl();
}
}
close_json_object();
@@ -461,7 +461,7 @@ static int tc_qdisc_block_exists_cb(struct nlmsghdr *n, void *arg)
if (len < 0)
return -1;
- parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);
+ parse_rtattr_flags(tb, TCA_MAX, TCA_RTA(t), len, NLA_F_NESTED);
if (tb[TCA_KIND] == NULL)
return -1;
diff --git a/tc/tc_util.c b/tc/tc_util.c
index 0e70632d7..5f13d729b 100644
--- a/tc/tc_util.c
+++ b/tc/tc_util.c
@@ -869,7 +869,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat
memcpy(&q, RTA_DATA(tbs[TCA_STATS_QUEUE]),
MIN(RTA_PAYLOAD(tbs[TCA_STATS_QUEUE]), sizeof(q)));
if (!tbs[TCA_STATS_RATE_EST])
- print_string(PRINT_FP, NULL, "\n", "");
+ print_nl();
print_uint(PRINT_JSON, "backlog", NULL, q.backlog);
print_string(PRINT_FP, NULL, "%s", prefix);
print_string(PRINT_FP, NULL, "backlog %s",