]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
Merge branch 'iproute2-master' into iproute2-next
authorDavid Ahern <dsahern@gmail.com>
Wed, 19 Dec 2018 20:02:17 +0000 (12:02 -0800)
committerDavid Ahern <dsahern@gmail.com>
Wed, 19 Dec 2018 20:02:17 +0000 (12:02 -0800)
Signed-off-by: David Ahern <dsahern@gmail.com>
43 files changed:
Makefile
README.decnet [deleted file]
README.lnstat
bash-completion/tc
devlink/devlink.c
include/json_print.h
include/json_writer.h
include/uapi/linux/devlink.h
include/uapi/linux/if_link.h
include/uapi/linux/pkt_cls.h
include/uapi/linux/pkt_sched.h
include/uapi/linux/sctp.h
include/uapi/linux/tcp.h
include/utils.h
ip/ip.c
ip/iplink_geneve.c
ip/iplink_vxlan.c
ip/iproute.c
ip/iprule.c
lib/dnet_ntop.c [deleted file]
lib/dnet_pton.c [deleted file]
lib/ipx_ntop.c [deleted file]
lib/ipx_pton.c [deleted file]
lib/json_print.c
lib/json_writer.c
lib/utils.c
man/man8/ip-link.8.in
man/man8/ip-route.8.in
man/man8/ip.8
man/man8/rdma-dev.8
man/man8/tc-flower.8
man/man8/tc-fq.8
rdma/dev.c
rdma/rdma.h
rdma/utils.c
tc/f_flower.c
tc/q_choke.c
tc/q_fq.c
tc/q_gred.c
tc/q_red.c
tc/q_sfq.c
tc/tc_red.c
tc/tc_red.h

index 20c760e24c9434c9f69d2093efab99657cfe0d4a..a513cf38ae6949b4457796d085ab6d8ca227cd7a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -40,12 +40,6 @@ DEFINES+=-DCONFDIR=\"$(CONFDIR)\" \
          -DNETNS_RUN_DIR=\"$(NETNS_RUN_DIR)\" \
          -DNETNS_ETC_DIR=\"$(NETNS_ETC_DIR)\"
 
-#options for decnet
-ADDLIB+=dnet_ntop.o dnet_pton.o
-
-#options for ipx
-ADDLIB+=ipx_ntop.o ipx_pton.o
-
 #options for mpls
 ADDLIB+=mpls_ntop.o mpls_pton.o
 
diff --git a/README.decnet b/README.decnet
deleted file mode 100644 (file)
index 4300f90..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-
-Here are a few quick points about DECnet support...
-
- o iproute2 is the tool of choice for configuring the DECnet support for
-   Linux. For many features, it is the only tool which can be used to
-   configure them.
-
- o No name resolution is available as yet, all addresses must be
-   entered numerically.
-
- o Remember to set the hardware address of the interface using: 
-
-   ip link set ethX address xx:xx:xx:xx:xx:xx
-      (where xx:xx:xx:xx:xx:xx is the MAC address for your DECnet node
-       address)
-
-   if your Ethernet card won't listen to more than one unicast
-   mac address at once. If the Linux DECnet stack doesn't talk to
-   any other DECnet nodes, then check this with tcpdump and if its
-   a problem, change the mac address (but do this _before_ starting
-   any other network protocol on the interface)
-
- o Whilst you can use ip addr add to add more than one DECnet address to an
-   interface, don't expect addresses which are not the same as the
-   kernels node address to work properly with 2.4 kernels. This should
-   be fine with 2.6 kernels as the routing code has been extensively
-   modified and improved.
-
- o The DECnet support is currently self contained. It does not depend on
-   the libdnet library.
-
-Steve Whitehouse <steve@chygwyn.com>
-
index 057925f671b7f5e65bb1309ccfae70530d0a3a55..59134a158c3bd6b91e874c17bdda1c0439781273 100644 (file)
@@ -9,7 +9,7 @@ In addition to routing cache statistics, it supports any kind of statistics
 the linux kernel exports via a file in /proc/net/stat.  In a stock 2.6.9
 kernel, this is 
        per-protocol neighbour cache statistics 
-               (ipv4, ipv6, atm, decnet)
+               (ipv4, ipv6, atm)
        routing cache statistics
                (ipv4)
        connection tracking statistics
index 29bca5d9354d3b7db65cba08ef84d3f8500cfa44..007e1c2e30bf48e4e48e98470ebfb36d190e0866 100644 (file)
@@ -302,7 +302,7 @@ _tc_qdisc_options()
             ;;
         gred)
             _tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \
-                burst probability bandwidth'
+                burst probability bandwidth ecn harddrop'
             return 0
             ;;
         hhf)
index 8bb254ea1b0b813c7c62991b4e8106fa579e6577..3651e90c115975d077c726c6611e2f0f9f9dc2cb 100644 (file)
@@ -1920,10 +1920,80 @@ static int cmd_dev_eswitch(struct dl *dl)
        return -ENOENT;
 }
 
-static void pr_out_param_value(struct dl *dl, int nla_type, struct nlattr *nl)
+struct param_val_conv {
+       const char *name;
+       const char *vstr;
+       uint32_t vuint;
+};
+
+static bool param_val_conv_exists(const struct param_val_conv *param_val_conv,
+                                 uint32_t len, const char *name)
+{
+       uint32_t i;
+
+       for (i = 0; i < len; i++)
+               if (!strcmp(param_val_conv[i].name, name))
+                       return true;
+
+       return false;
+}
+
+static int
+param_val_conv_uint_get(const struct param_val_conv *param_val_conv,
+                       uint32_t len, const char *name, const char *vstr,
+                       uint32_t *vuint)
+{
+       uint32_t i;
+
+       for (i = 0; i < len; i++)
+               if (!strcmp(param_val_conv[i].name, name) &&
+                   !strcmp(param_val_conv[i].vstr, vstr)) {
+                       *vuint = param_val_conv[i].vuint;
+                       return 0;
+               }
+
+       return -ENOENT;
+}
+
+static int
+param_val_conv_str_get(const struct param_val_conv *param_val_conv,
+                      uint32_t len, const char *name, uint32_t vuint,
+                      const char **vstr)
+{
+       uint32_t i;
+
+       for (i = 0; i < len; i++)
+               if (!strcmp(param_val_conv[i].name, name) &&
+                   param_val_conv[i].vuint == vuint) {
+                       *vstr = param_val_conv[i].vstr;
+                       return 0;
+               }
+
+       return -ENOENT;
+}
+
+static const struct param_val_conv param_val_conv[] = {
+       {
+               .name = "fw_load_policy",
+               .vstr = "driver",
+               .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
+       },
+       {
+               .name = "fw_load_policy",
+               .vstr = "flash",
+               .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
+       },
+};
+
+#define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
+
+static void pr_out_param_value(struct dl *dl, const char *nla_name,
+                              int nla_type, struct nlattr *nl)
 {
        struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
        struct nlattr *val_attr;
+       const char *vstr;
+       bool conv_exists;
        int err;
 
        err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
@@ -1939,15 +2009,51 @@ static void pr_out_param_value(struct dl *dl, int nla_type, struct nlattr *nl)
                   param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
        val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
 
+       conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
+                                           nla_name);
+
        switch (nla_type) {
        case MNL_TYPE_U8:
-               pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
+               if (conv_exists) {
+                       err = param_val_conv_str_get(param_val_conv,
+                                                    PARAM_VAL_CONV_LEN,
+                                                    nla_name,
+                                                    mnl_attr_get_u8(val_attr),
+                                                    &vstr);
+                       if (err)
+                               return;
+                       pr_out_str(dl, "value", vstr);
+               } else {
+                       pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
+               }
                break;
        case MNL_TYPE_U16:
-               pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
+               if (conv_exists) {
+                       err = param_val_conv_str_get(param_val_conv,
+                                                    PARAM_VAL_CONV_LEN,
+                                                    nla_name,
+                                                    mnl_attr_get_u16(val_attr),
+                                                    &vstr);
+                       if (err)
+                               return;
+                       pr_out_str(dl, "value", vstr);
+               } else {
+                       pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
+               }
                break;
        case MNL_TYPE_U32:
-               pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
+               if (conv_exists) {
+                       err = param_val_conv_str_get(param_val_conv,
+                                                    PARAM_VAL_CONV_LEN,
+                                                    nla_name,
+                                                    mnl_attr_get_u32(val_attr),
+                                                    &vstr);
+                       if (err)
+                               return;
+                       pr_out_str(dl, "value", vstr);
+               } else {
+                       pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
+               }
                break;
        case MNL_TYPE_STRING:
                pr_out_str(dl, "value", mnl_attr_get_str(val_attr));
@@ -1962,6 +2068,7 @@ static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
 {
        struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
        struct nlattr *param_value_attr;
+       const char *nla_name;
        int nla_type;
        int err;
 
@@ -1980,8 +2087,8 @@ static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
 
        nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
 
-       pr_out_str(dl, "name",
-                  mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]));
+       nla_name = mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]);
+       pr_out_str(dl, "name", nla_name);
 
        if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
                pr_out_str(dl, "type", "driver-specific");
@@ -1992,7 +2099,7 @@ static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
        mnl_attr_for_each_nested(param_value_attr,
                                 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
                pr_out_entry_start(dl);
-               pr_out_param_value(dl, nla_type, param_value_attr);
+               pr_out_param_value(dl, nla_name, nla_type, param_value_attr);
                pr_out_entry_end(dl);
        }
        pr_out_array_end(dl);
@@ -2097,6 +2204,7 @@ static int cmd_dev_param_set(struct dl *dl)
 {
        struct param_ctx ctx = {};
        struct nlmsghdr *nlh;
+       bool conv_exists;
        uint32_t val_u32;
        uint16_t val_u16;
        uint8_t val_u8;
@@ -2124,10 +2232,22 @@ static int cmd_dev_param_set(struct dl *dl)
                               NLM_F_REQUEST | NLM_F_ACK);
        dl_opts_put(nlh, dl);
 
+       conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
+                                           dl->opts.param_name);
+
        mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
        switch (ctx.nla_type) {
        case MNL_TYPE_U8:
-               err = strtouint8_t(dl->opts.param_value, &val_u8);
+               if (conv_exists) {
+                       err = param_val_conv_uint_get(param_val_conv,
+                                                     PARAM_VAL_CONV_LEN,
+                                                     dl->opts.param_name,
+                                                     dl->opts.param_value,
+                                                     &val_u32);
+                       val_u8 = val_u32;
+               } else {
+                       err = strtouint8_t(dl->opts.param_value, &val_u8);
+               }
                if (err)
                        goto err_param_value_parse;
                if (val_u8 == ctx.value.vu8)
@@ -2135,7 +2255,16 @@ static int cmd_dev_param_set(struct dl *dl)
                mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
                break;
        case MNL_TYPE_U16:
-               err = strtouint16_t(dl->opts.param_value, &val_u16);
+               if (conv_exists) {
+                       err = param_val_conv_uint_get(param_val_conv,
+                                                     PARAM_VAL_CONV_LEN,
+                                                     dl->opts.param_name,
+                                                     dl->opts.param_value,
+                                                     &val_u32);
+                       val_u16 = val_u32;
+               } else {
+                       err = strtouint16_t(dl->opts.param_value, &val_u16);
+               }
                if (err)
                        goto err_param_value_parse;
                if (val_u16 == ctx.value.vu16)
@@ -2143,7 +2272,14 @@ static int cmd_dev_param_set(struct dl *dl)
                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
                break;
        case MNL_TYPE_U32:
-               err = strtouint32_t(dl->opts.param_value, &val_u32);
+               if (conv_exists)
+                       err = param_val_conv_uint_get(param_val_conv,
+                                                     PARAM_VAL_CONV_LEN,
+                                                     dl->opts.param_name,
+                                                     dl->opts.param_value,
+                                                     &val_u32);
+               else
+                       err = strtouint32_t(dl->opts.param_value, &val_u32);
                if (err)
                        goto err_param_value_parse;
                if (val_u32 == ctx.value.vu32)
index ee087c3e627a73ffc70de465f7e94325ef824e21..dbdc90e2316ab7ed7c1ec9a133a7c069f9b15cda 100644 (file)
@@ -64,6 +64,7 @@ _PRINT_FUNC(null, const char*);
 _PRINT_FUNC(string, const char*);
 _PRINT_FUNC(uint, unsigned int);
 _PRINT_FUNC(u64, uint64_t);
+_PRINT_FUNC(hhu, unsigned char);
 _PRINT_FUNC(hu, unsigned short);
 _PRINT_FUNC(hex, unsigned int);
 _PRINT_FUNC(0xhex, unsigned long long);
index 17d409e0557d3b7d30a7456e1db13073dbc209ad..b52dc2d08a2f6b0fb5a14abe4cbaed56b965a3e6 100644 (file)
@@ -38,6 +38,7 @@ void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num);
 void jsonw_uint(json_writer_t *self, unsigned int number);
 void jsonw_u64(json_writer_t *self, uint64_t number);
 void jsonw_xint(json_writer_t *self, uint64_t number);
+void jsonw_hhu(json_writer_t *self, unsigned char num);
 void jsonw_hu(json_writer_t *self, unsigned short number);
 void jsonw_int(json_writer_t *self, int number);
 void jsonw_s64(json_writer_t *self, int64_t number);
@@ -52,6 +53,7 @@ void jsonw_float_field(json_writer_t *self, const char *prop, double num);
 void jsonw_uint_field(json_writer_t *self, const char *prop, unsigned int num);
 void jsonw_u64_field(json_writer_t *self, const char *prop, uint64_t num);
 void jsonw_xint_field(json_writer_t *self, const char *prop, uint64_t num);
+void jsonw_hhu_field(json_writer_t *self, const char *prop, unsigned char 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, int num);
 void jsonw_s64_field(json_writer_t *self, const char *prop, int64_t num);
index 5ee0e7397591adcbfaee84d199dcf5f9fa229a95..d0a33d79dc221379ae23fba1bca40034b65417f5 100644 (file)
@@ -163,6 +163,11 @@ enum devlink_param_cmode {
        DEVLINK_PARAM_CMODE_MAX = __DEVLINK_PARAM_CMODE_MAX - 1
 };
 
+enum devlink_param_fw_load_policy_value {
+       DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
+       DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
+};
+
 enum devlink_attr {
        /* don't change the order or add anything between, this is ABI! */
        DEVLINK_ATTR_UNSPEC,
index 52e95197e07902c5d6f0fcadeab5fd8df1e70246..e1ef848aed011d3fc4f7cbefb30ee528c0a027bc 100644 (file)
@@ -531,6 +531,7 @@ enum {
        IFLA_VXLAN_LABEL,
        IFLA_VXLAN_GPE,
        IFLA_VXLAN_TTL_INHERIT,
+       IFLA_VXLAN_DF,
        __IFLA_VXLAN_MAX
 };
 #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
@@ -540,6 +541,14 @@ struct ifla_vxlan_port_range {
        __be16  high;
 };
 
+enum ifla_vxlan_df {
+       VXLAN_DF_UNSET = 0,
+       VXLAN_DF_SET,
+       VXLAN_DF_INHERIT,
+       __VXLAN_DF_END,
+       VXLAN_DF_MAX = __VXLAN_DF_END - 1,
+};
+
 /* GENEVE section */
 enum {
        IFLA_GENEVE_UNSPEC,
@@ -555,10 +564,19 @@ enum {
        IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
        IFLA_GENEVE_LABEL,
        IFLA_GENEVE_TTL_INHERIT,
+       IFLA_GENEVE_DF,
        __IFLA_GENEVE_MAX
 };
 #define IFLA_GENEVE_MAX        (__IFLA_GENEVE_MAX - 1)
 
+enum ifla_geneve_df {
+       GENEVE_DF_UNSET = 0,
+       GENEVE_DF_SET,
+       GENEVE_DF_INHERIT,
+       __GENEVE_DF_END,
+       GENEVE_DF_MAX = __GENEVE_DF_END - 1,
+};
+
 /* PPP section */
 enum {
        IFLA_PPP_UNSPEC,
index 401d0c1e612d3a291688cf6f90e4d2803f7c09dd..95d0db2a8350dffb1dd20816591f3b179913fb2e 100644 (file)
@@ -485,6 +485,11 @@ enum {
 
        TCA_FLOWER_IN_HW_COUNT,
 
+       TCA_FLOWER_KEY_PORT_SRC_MIN,    /* be16 */
+       TCA_FLOWER_KEY_PORT_SRC_MAX,    /* be16 */
+       TCA_FLOWER_KEY_PORT_DST_MIN,    /* be16 */
+       TCA_FLOWER_KEY_PORT_DST_MAX,    /* be16 */
+
        __TCA_FLOWER_MAX,
 };
 
@@ -518,6 +523,8 @@ enum {
        TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
 };
 
+#define TCA_FLOWER_MASK_FLAGS_RANGE    (1 << 0) /* Range-based match */
+
 /* Match-all classifier */
 
 enum {
index 89ee47c2f17d86fba9a37733b5593680ceefcf00..0d18b1d1fbbc8a845857461b7baa3522636dbf31 100644 (file)
@@ -291,11 +291,38 @@ enum {
        TCA_GRED_DPS,
        TCA_GRED_MAX_P,
        TCA_GRED_LIMIT,
+       TCA_GRED_VQ_LIST,       /* nested TCA_GRED_VQ_ENTRY */
        __TCA_GRED_MAX,
 };
 
 #define TCA_GRED_MAX (__TCA_GRED_MAX - 1)
 
+enum {
+       TCA_GRED_VQ_ENTRY_UNSPEC,
+       TCA_GRED_VQ_ENTRY,      /* nested TCA_GRED_VQ_* */
+       __TCA_GRED_VQ_ENTRY_MAX,
+};
+#define TCA_GRED_VQ_ENTRY_MAX (__TCA_GRED_VQ_ENTRY_MAX - 1)
+
+enum {
+       TCA_GRED_VQ_UNSPEC,
+       TCA_GRED_VQ_PAD,
+       TCA_GRED_VQ_DP,                 /* u32 */
+       TCA_GRED_VQ_STAT_BYTES,         /* u64 */
+       TCA_GRED_VQ_STAT_PACKETS,       /* u32 */
+       TCA_GRED_VQ_STAT_BACKLOG,       /* u32 */
+       TCA_GRED_VQ_STAT_PROB_DROP,     /* u32 */
+       TCA_GRED_VQ_STAT_PROB_MARK,     /* u32 */
+       TCA_GRED_VQ_STAT_FORCED_DROP,   /* u32 */
+       TCA_GRED_VQ_STAT_FORCED_MARK,   /* u32 */
+       TCA_GRED_VQ_STAT_PDROP,         /* u32 */
+       TCA_GRED_VQ_STAT_OTHER,         /* u32 */
+       TCA_GRED_VQ_FLAGS,              /* u32 */
+       __TCA_GRED_VQ_MAX
+};
+
+#define TCA_GRED_VQ_MAX (__TCA_GRED_VQ_MAX - 1)
+
 struct tc_gred_qopt {
        __u32           limit;        /* HARD maximal queue length (bytes)    */
        __u32           qth_min;      /* Min average length threshold (bytes) */
@@ -864,6 +891,8 @@ enum {
 
        TCA_FQ_LOW_RATE_THRESHOLD, /* per packet delay under this rate */
 
+       TCA_FQ_CE_THRESHOLD,    /* DCTCP-like CE-marking threshold */
+
        __TCA_FQ_MAX
 };
 
@@ -882,6 +911,7 @@ struct tc_fq_qd_stats {
        __u32   inactive_flows;
        __u32   throttled_flows;
        __u32   unthrottle_latency_ns;
+       __u64   ce_mark;                /* packets above ce_threshold */
 };
 
 /* Heavy-Hitter Filter */
index c4d3a8a2bdae4eac829cdf8cbfe1cc3d602276e9..e9970b69d56075556c22754579ec3265bfb0fa9e 100644 (file)
@@ -129,6 +129,7 @@ typedef __s32 sctp_assoc_t;
 #define SCTP_STREAM_SCHEDULER_VALUE    124
 #define SCTP_INTERLEAVING_SUPPORTED    125
 #define SCTP_SENDMSG_CONNECT   126
+#define SCTP_EVENT     127
 
 /* PR-SCTP policies */
 #define SCTP_PR_SCTP_NONE      0x0000
@@ -632,7 +633,9 @@ union sctp_notification {
  */
 
 enum sctp_sn_type {
-       SCTP_SN_TYPE_BASE     = (1<<15),
+       SCTP_SN_TYPE_BASE       = (1<<15),
+       SCTP_DATA_IO_EVENT      = SCTP_SN_TYPE_BASE,
+#define SCTP_DATA_IO_EVENT             SCTP_DATA_IO_EVENT
        SCTP_ASSOC_CHANGE,
 #define SCTP_ASSOC_CHANGE              SCTP_ASSOC_CHANGE
        SCTP_PEER_ADDR_CHANGE,
@@ -657,6 +660,8 @@ enum sctp_sn_type {
 #define SCTP_ASSOC_RESET_EVENT         SCTP_ASSOC_RESET_EVENT
        SCTP_STREAM_CHANGE_EVENT,
 #define SCTP_STREAM_CHANGE_EVENT       SCTP_STREAM_CHANGE_EVENT
+       SCTP_SN_TYPE_MAX        = SCTP_STREAM_CHANGE_EVENT,
+#define SCTP_SN_TYPE_MAX               SCTP_SN_TYPE_MAX
 };
 
 /* Notification error codes used to fill up the error fields in some
@@ -1144,6 +1149,12 @@ struct sctp_add_streams {
        uint16_t sas_outstrms;
 };
 
+struct sctp_event {
+       sctp_assoc_t se_assoc_id;
+       uint16_t se_type;
+       uint8_t se_on;
+};
+
 /* SCTP Stream schedulers */
 enum sctp_sched_type {
        SCTP_SS_FCFS,
index 6ec776621806bf5ca2756b916e33da78f5a36ccc..799b5c5fd49e32dafd40774a3e9328cd96e209d8 100644 (file)
@@ -266,6 +266,7 @@ enum {
        TCP_NLA_BYTES_RETRANS,  /* Data bytes retransmitted */
        TCP_NLA_DSACK_DUPS,     /* DSACK blocks received */
        TCP_NLA_REORD_SEEN,     /* reordering events seen */
+       TCP_NLA_SRTT,           /* smoothed RTT in usecs */
 };
 
 /* for TCP_MD5SIG socket option */
index 1630dd0b28540c87fb285c51a9197f246301b630..92bbe82d3366b175aea90674c40c1b25ce995308 100644 (file)
@@ -116,13 +116,6 @@ struct dn_naddr
         unsigned char a_addr[DN_MAXADDL];
 };
 
-#define IPX_NODE_LEN 6
-
-struct ipx_addr {
-       u_int32_t ipx_net;
-       u_int8_t  ipx_node[IPX_NODE_LEN];
-};
-
 #ifndef AF_MPLS
 # define AF_MPLS 28
 #endif
@@ -201,12 +194,6 @@ int matches(const char *arg, const char *pattern);
 int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits);
 int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta);
 
-const char *dnet_ntop(int af, const void *addr, char *str, size_t len);
-int dnet_pton(int af, const char *src, void *addr);
-
-const char *ipx_ntop(int af, const void *addr, char *str, size_t len);
-int ipx_pton(int af, const char *src, void *addr);
-
 const char *mpls_ntop(int af, const void *addr, char *str, size_t len);
 int mpls_pton(int af, const char *src, void *addr, size_t alen);
 
diff --git a/ip/ip.c b/ip/ip.c
index c324120f9fc59991ac82bb9420679c9bc972f993..a5bbacb4bb0f589a8305279b66a571c9d1bc1af4 100644 (file)
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -53,7 +53,7 @@ static void usage(void)
 "                   vrf | sr }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
 "                    -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
-"                    -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
+"                    -f[amily] { inet | inet6 | mpls | bridge | link } |\n"
 "                    -4 | -6 | -I | -D | -M | -B | -0 |\n"
 "                    -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
 "                    -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
@@ -225,8 +225,6 @@ int main(int argc, char **argv)
                        preferred_family = AF_INET6;
                } else if (strcmp(opt, "-0") == 0) {
                        preferred_family = AF_PACKET;
-               } else if (strcmp(opt, "-I") == 0) {
-                       preferred_family = AF_IPX;
                } else if (strcmp(opt, "-D") == 0) {
                        preferred_family = AF_DECnet;
                } else if (strcmp(opt, "-M") == 0) {
index f1a12f454ab728e5a8862518c3d0987b2f18ec3e..278a6e23b311a629eaeadd2c40c593d5c60a8ef8 100644 (file)
@@ -24,6 +24,7 @@ static void print_explain(FILE *f)
                "                  remote ADDR\n"
                "                  [ ttl TTL ]\n"
                "                  [ tos TOS ]\n"
+               "                  [ df DF ]\n"
                "                  [ flowlabel LABEL ]\n"
                "                  [ dstport PORT ]\n"
                "                  [ [no]external ]\n"
@@ -35,6 +36,7 @@ static void print_explain(FILE *f)
                "       ADDR  := IP_ADDRESS\n"
                "       TOS   := { NUMBER | inherit }\n"
                "       TTL   := { 1..255 | auto | inherit }\n"
+               "       DF    := { unset | set | inherit }\n"
                "       LABEL := 0-1048575\n"
        );
 }
@@ -115,6 +117,22 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
                                tos = uval;
                        } else
                                tos = 1;
+               } else if (!matches(*argv, "df")) {
+                       enum ifla_geneve_df df;
+
+                       NEXT_ARG();
+                       check_duparg(&attrs, IFLA_GENEVE_DF, "df", *argv);
+                       if (strcmp(*argv, "unset") == 0)
+                               df = GENEVE_DF_UNSET;
+                       else if (strcmp(*argv, "set") == 0)
+                               df = GENEVE_DF_SET;
+                       else if (strcmp(*argv, "inherit") == 0)
+                               df = GENEVE_DF_INHERIT;
+                       else
+                               invarg("DF must be 'unset', 'set' or 'inherit'",
+                                      *argv);
+
+                       addattr8(n, 1024, IFLA_GENEVE_DF, df);
                } else if (!matches(*argv, "label") ||
                           !matches(*argv, "flowlabel")) {
                        __u32 uval;
@@ -287,6 +305,17 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        print_string(PRINT_FP, NULL, "tos %s ", "inherit");
        }
 
+       if (tb[IFLA_GENEVE_DF]) {
+               enum ifla_geneve_df df = rta_getattr_u8(tb[IFLA_GENEVE_DF]);
+
+               if (df == GENEVE_DF_UNSET)
+                       print_string(PRINT_JSON, "df", "df %s ", "unset");
+               else if (df == GENEVE_DF_SET)
+                       print_string(PRINT_ANY, "df", "df %s ", "set");
+               else if (df == GENEVE_DF_INHERIT)
+                       print_string(PRINT_ANY, "df", "df %s ", "inherit");
+       }
+
        if (tb[IFLA_GENEVE_LABEL]) {
                __u32 label = rta_getattr_u32(tb[IFLA_GENEVE_LABEL]);
 
index 62e769430c5d377d9307d1882493dd5ddf7feb41..497affc0c90b36492ddb7c1259e4760679fe1739 100644 (file)
@@ -31,6 +31,7 @@ static void print_explain(FILE *f)
                "                 [ local ADDR ]\n"
                "                 [ ttl TTL ]\n"
                "                 [ tos TOS ]\n"
+               "                 [ df DF ]\n"
                "                 [ flowlabel LABEL ]\n"
                "                 [ dev PHYS_DEV ]\n"
                "                 [ dstport PORT ]\n"
@@ -52,6 +53,7 @@ static void print_explain(FILE *f)
                "       ADDR  := { IP_ADDRESS | any }\n"
                "       TOS   := { NUMBER | inherit }\n"
                "       TTL   := { 1..255 | auto | inherit }\n"
+               "       DF    := { unset | set | inherit }\n"
                "       LABEL := 0-1048575\n"
        );
 }
@@ -170,6 +172,22 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
                        } else
                                tos = 1;
                        addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
+               } else if (!matches(*argv, "df")) {
+                       enum ifla_vxlan_df df;
+
+                       NEXT_ARG();
+                       check_duparg(&attrs, IFLA_VXLAN_DF, "df", *argv);
+                       if (strcmp(*argv, "unset") == 0)
+                               df = VXLAN_DF_UNSET;
+                       else if (strcmp(*argv, "set") == 0)
+                               df = VXLAN_DF_SET;
+                       else if (strcmp(*argv, "inherit") == 0)
+                               df = VXLAN_DF_INHERIT;
+                       else
+                               invarg("DF must be 'unset', 'set' or 'inherit'",
+                                      *argv);
+
+                       addattr8(n, 1024, IFLA_VXLAN_DF, df);
                } else if (!matches(*argv, "label") ||
                           !matches(*argv, "flowlabel")) {
                        __u32 uval;
@@ -538,6 +556,17 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        print_string(PRINT_FP, NULL, "ttl %s ", "auto");
        }
 
+       if (tb[IFLA_VXLAN_DF]) {
+               enum ifla_vxlan_df df = rta_getattr_u8(tb[IFLA_VXLAN_DF]);
+
+               if (df == VXLAN_DF_UNSET)
+                       print_string(PRINT_JSON, "df", "df %s ", "unset");
+               else if (df == VXLAN_DF_SET)
+                       print_string(PRINT_ANY, "df", "df %s ", "set");
+               else if (df == VXLAN_DF_INHERIT)
+                       print_string(PRINT_ANY, "df", "df %s ", "inherit");
+       }
+
        if (tb[IFLA_VXLAN_LABEL]) {
                __u32 label = rta_getattr_u32(tb[IFLA_VXLAN_LABEL]);
 
index fa6a84b59a5c7d2ecaef60a7b7566a5fde530be4..d347246925531ead5e7a6eb40e9bdbbfcb9b4bc2 100644 (file)
@@ -83,7 +83,7 @@ static void usage(void)
                "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n"
                "NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]\n"
                "           [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"
-               "FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]\n"
+               "FAMILY := [ inet | inet6 | mpls | bridge | link ]\n"
                "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n"
                "           [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"
                "           [ window NUMBER ] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"
index 0f8fc6d99136ef647c323c5e34f95f27dc1b2e1f..6af71cab653479f3c467958f70d169fb7c963817 100644 (file)
@@ -78,6 +78,9 @@ static struct
        inet_prefix dst;
        int protocol;
        int protocolmask;
+       struct fib_rule_port_range sport;
+       struct fib_rule_port_range dport;
+       __u8 ipproto;
 } filter;
 
 static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
@@ -174,6 +177,39 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
                        return false;
        }
 
+       if (filter.ipproto) {
+               __u8 ipproto = 0;
+
+               if (tb[FRA_IP_PROTO])
+                       ipproto = rta_getattr_u8(tb[FRA_IP_PROTO]);
+               if (filter.ipproto != ipproto)
+                       return false;
+       }
+
+       if (filter.sport.start) {
+               const struct fib_rule_port_range *r;
+
+               if (!tb[FRA_SPORT_RANGE])
+                       return false;
+
+               r = RTA_DATA(tb[FRA_SPORT_RANGE]);
+               if (r->start != filter.sport.start ||
+                   r->end != filter.sport.end)
+                       return false;
+       }
+
+       if (filter.dport.start) {
+               const struct fib_rule_port_range *r;
+
+               if (!tb[FRA_DPORT_RANGE])
+                       return false;
+
+               r = RTA_DATA(tb[FRA_DPORT_RANGE]);
+               if (r->start != filter.dport.start ||
+                   r->end != filter.dport.end)
+                       return false;
+       }
+
        table = frh_get_table(frh, tb);
        if (filter.tb > 0 && filter.tb ^ table)
                return false;
@@ -607,6 +643,36 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
                                filter.protocolmask = 0;
                        }
                        filter.protocol = prot;
+               } else if (strcmp(*argv, "ipproto") == 0) {
+                       int ipproto;
+
+                       NEXT_ARG();
+                       ipproto = inet_proto_a2n(*argv);
+                       if (ipproto < 0)
+                               invarg("Invalid \"ipproto\" value\n", *argv);
+                       filter.ipproto = ipproto;
+               } else if (strcmp(*argv, "sport") == 0) {
+                       struct fib_rule_port_range r;
+                       int ret;
+
+                       NEXT_ARG();
+                       ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+                       if (ret == 1)
+                               r.end = r.start;
+                       else if (ret != 2)
+                               invarg("invalid port range\n", *argv);
+                       filter.sport = r;
+               } else if (strcmp(*argv, "dport") == 0) {
+                       struct fib_rule_port_range r;
+                       int ret;
+
+                       NEXT_ARG();
+                       ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+                       if (ret == 1)
+                               r.end = r.start;
+                       else if (ret != 2)
+                               invarg("invalid dport range\n", *argv);
+                       filter.dport = r;
                } else{
                        if (matches(*argv, "dst") == 0 ||
                            matches(*argv, "to") == 0) {
diff --git a/lib/dnet_ntop.c b/lib/dnet_ntop.c
deleted file mode 100644 (file)
index 17d960e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-
-#include "utils.h"
-
-static __inline__ u_int16_t dn_ntohs(u_int16_t addr)
-{
-       union {
-               u_int8_t byte[2];
-               u_int16_t word;
-       } u;
-
-       u.word = addr;
-       return ((u_int16_t)u.byte[0]) | (((u_int16_t)u.byte[1]) << 8);
-}
-
-static __inline__ int do_digit(char *str, u_int16_t *addr, u_int16_t scale, size_t *pos, size_t len, int *started)
-{
-       u_int16_t tmp = *addr / scale;
-
-       if (*pos == len)
-               return 1;
-
-       if (((tmp) > 0) || *started || (scale == 1)) {
-               *str = tmp + '0';
-               *started = 1;
-               (*pos)++;
-               *addr -= (tmp * scale);
-       }
-
-       return 0;
-}
-
-
-static const char *dnet_ntop1(const struct dn_naddr *dna, char *str, size_t len)
-{
-       u_int16_t addr, area;
-       size_t pos = 0;
-       int started = 0;
-
-       memcpy(&addr, dna->a_addr, sizeof(addr));
-       addr = dn_ntohs(addr);
-       area = addr >> 10;
-
-       if (dna->a_len != 2)
-               return NULL;
-
-       addr &= 0x03ff;
-
-       if (len == 0)
-               return str;
-
-       if (do_digit(str + pos, &area, 10, &pos, len, &started))
-               return str;
-
-       if (do_digit(str + pos, &area, 1, &pos, len, &started))
-               return str;
-
-       if (pos == len)
-               return str;
-
-       *(str + pos) = '.';
-       pos++;
-       started = 0;
-
-       if (do_digit(str + pos, &addr, 1000, &pos, len, &started))
-               return str;
-
-       if (do_digit(str + pos, &addr, 100, &pos, len, &started))
-               return str;
-
-       if (do_digit(str + pos, &addr, 10, &pos, len, &started))
-               return str;
-
-       if (do_digit(str + pos, &addr, 1, &pos, len, &started))
-               return str;
-
-       if (pos == len)
-               return str;
-
-       *(str + pos) = 0;
-
-       return str;
-}
-
-
-const char *dnet_ntop(int af, const void *addr, char *str, size_t len)
-{
-       switch(af) {
-               case AF_DECnet:
-                       errno = 0;
-                       return dnet_ntop1((struct dn_naddr *)addr, str, len);
-               default:
-                       errno = EAFNOSUPPORT;
-       }
-
-       return NULL;
-}
diff --git a/lib/dnet_pton.c b/lib/dnet_pton.c
deleted file mode 100644 (file)
index 1cf54e5..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-
-#include "utils.h"
-
-static __inline__ u_int16_t dn_htons(u_int16_t addr)
-{
-        union {
-                u_int8_t byte[2];
-                u_int16_t word;
-        } u;
-
-        u.word = addr;
-        return ((u_int16_t)u.byte[0]) | (((u_int16_t)u.byte[1]) << 8);
-}
-
-
-static int dnet_num(const char *src, u_int16_t * dst)
-{
-       int rv = 0;
-       int tmp;
-       *dst = 0;
-
-       while ((tmp = *src++) != 0) {
-               tmp -= '0';
-               if ((tmp < 0) || (tmp > 9))
-                       return rv;
-
-               rv++;
-               (*dst) *= 10;
-               (*dst) += tmp;
-       }
-
-       return rv;
-}
-
-static int dnet_pton1(const char *src, struct dn_naddr *dna)
-{
-       u_int16_t addr;
-       u_int16_t area = 0;
-       u_int16_t node = 0;
-       int pos;
-
-       pos = dnet_num(src, &area);
-       if ((pos == 0) || (area > 63) || (*(src + pos) != '.'))
-               return 0;
-       pos = dnet_num(src + pos + 1, &node);
-       if ((pos == 0) || (node > 1023))
-               return 0;
-       dna->a_len = 2;
-       addr = dn_htons((area << 10) | node);
-       memcpy(dna->a_addr, &addr, sizeof(addr));
-
-       return 1;
-}
-
-int dnet_pton(int af, const char *src, void *addr)
-{
-       int err;
-
-       switch (af) {
-       case AF_DECnet:
-               errno = 0;
-               err = dnet_pton1(src, (struct dn_naddr *)addr);
-               break;
-       default:
-               errno = EAFNOSUPPORT;
-               err = -1;
-       }
-
-       return err;
-}
diff --git a/lib/ipx_ntop.c b/lib/ipx_ntop.c
deleted file mode 100644 (file)
index 80b8a34..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include "utils.h"
-
-static __inline__ int do_digit(char *str, u_int32_t addr, u_int32_t scale, size_t *pos, size_t len)
-{
-       u_int32_t tmp = addr >> (scale * 4);
-
-       if (*pos == len)
-               return 1;
-
-       tmp &= 0x0f;
-       if (tmp > 9)
-               *str = tmp + 'A' - 10;
-       else
-               *str = tmp + '0';
-       (*pos)++;
-
-       return 0;
-}
-
-static const char *ipx_ntop1(const struct ipx_addr *addr, char *str, size_t len)
-{
-       int i;
-       size_t pos = 0;
-
-       if (len == 0)
-               return str;
-
-       for(i = 7; i >= 0; i--)
-               if (do_digit(str + pos, ntohl(addr->ipx_net), i, &pos, len))
-                       return str;
-
-       if (pos == len)
-               return str;
-
-       *(str + pos) = '.';
-       pos++;
-
-       for(i = 0; i < 6; i++) {
-               if (do_digit(str + pos, addr->ipx_node[i], 1, &pos, len))
-                       return str;
-               if (do_digit(str + pos, addr->ipx_node[i], 0, &pos, len))
-                       return str;
-       }
-
-       if (pos == len)
-               return str;
-
-       *(str + pos) = 0;
-
-       return str;
-}
-
-
-const char *ipx_ntop(int af, const void *addr, char *str, size_t len)
-{
-       switch(af) {
-               case AF_IPX:
-                       errno = 0;
-                       return ipx_ntop1((struct ipx_addr *)addr, str, len);
-               default:
-                       errno = EAFNOSUPPORT;
-       }
-
-       return NULL;
-}
diff --git a/lib/ipx_pton.c b/lib/ipx_pton.c
deleted file mode 100644 (file)
index a97c1c1..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include "utils.h"
-
-static int ipx_getnet(u_int32_t *net, const char *str)
-{
-       int i;
-       u_int32_t tmp;
-
-       for(i = 0; *str && (i < 8); i++) {
-
-               if ((tmp = get_hex(*str)) == -1) {
-                       if (*str == '.')
-                               return 0;
-                       else
-                               return -1;
-               }
-
-               str++;
-               (*net) <<= 4;
-               (*net) |= tmp;
-       }
-
-       if (*str == 0)
-               return 0;
-
-       return -1;
-}
-
-static int ipx_getnode(u_int8_t *node, const char *str)
-{
-       int i;
-       u_int32_t tmp;
-
-       for(i = 0; i < 6; i++) {
-               if ((tmp = get_hex(*str++)) == -1)
-                       return -1;
-               node[i] = (u_int8_t)tmp;
-               node[i] <<= 4;
-               if ((tmp = get_hex(*str++)) == -1)
-                       return -1;
-               node[i] |= (u_int8_t)tmp;
-               if (*str == ':')
-                       str++;
-       }
-
-       return 0;
-}
-
-static int ipx_pton1(const char *src, struct ipx_addr *addr)
-{
-       char *sep = (char *)src;
-       int no_node = 0;
-
-       memset(addr, 0, sizeof(struct ipx_addr));
-
-       while(*sep && (*sep != '.'))
-               sep++;
-
-       if (*sep != '.')
-               no_node = 1;
-
-       if (ipx_getnet(&addr->ipx_net, src))
-               return 0;
-
-       addr->ipx_net = htonl(addr->ipx_net);
-
-       if (no_node)
-               return 1;
-
-       if (ipx_getnode(addr->ipx_node, sep + 1))
-               return 0;
-
-       return 1;
-}
-
-int ipx_pton(int af, const char *src, void *addr)
-{
-       int err;
-
-       switch (af) {
-       case AF_IPX:
-               errno = 0;
-               err = ipx_pton1(src, (struct ipx_addr *)addr);
-               break;
-       default:
-               errno = EAFNOSUPPORT;
-               err = -1;
-       }
-
-       return err;
-}
index 54fa40cff142762b94aadc3b855e83d5c3ecfb10..4eb2d0dc3c848b2d7d64ee3da402c5894546160f 100644 (file)
@@ -118,6 +118,7 @@ void close_json_array(enum output_type type, const char *str)
        }
 _PRINT_FUNC(int, int);
 _PRINT_FUNC(s64, int64_t);
+_PRINT_FUNC(hhu, unsigned char);
 _PRINT_FUNC(hu, unsigned short);
 _PRINT_FUNC(uint, unsigned int);
 _PRINT_FUNC(u64, uint64_t);
index 5779ec067daa2fd36019987e813c89605cc47fe8..5004c181e6225bb2e4e3aba4859ee7ebce42445d 100644 (file)
@@ -211,6 +211,11 @@ void jsonw_float(json_writer_t *self, double num)
        jsonw_printf(self, "%g", num);
 }
 
+void jsonw_hhu(json_writer_t *self, unsigned char num)
+{
+       jsonw_printf(self, "%hhu", num);
+}
+
 void jsonw_hu(json_writer_t *self, unsigned short num)
 {
        jsonw_printf(self, "%hu", num);
@@ -288,6 +293,12 @@ void jsonw_xint_field(json_writer_t *self, const char *prop, uint64_t num)
        jsonw_xint(self, num);
 }
 
+void jsonw_hhu_field(json_writer_t *self, const char *prop, unsigned char num)
+{
+       jsonw_name(self, prop);
+       jsonw_hhu(self, num);
+}
+
 void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
 {
        jsonw_name(self, prop);
index 84733890587d234b792ab2745f6d566ccdbfc3c5..a81c070069fedecab440e57756aa018bc0eee321 100644 (file)
@@ -600,18 +600,6 @@ static int __get_addr_1(inet_prefix *addr, const char *name, int family)
                return 0;
        }
 
-       if (family == AF_DECnet) {
-               struct dn_naddr dna;
-
-               addr->family = AF_DECnet;
-               if (dnet_pton(AF_DECnet, name, &dna) <= 0)
-                       return -1;
-               memcpy(addr->data, dna.a_addr, 2);
-               addr->bytelen = 2;
-               addr->bitlen = -1;
-               return 0;
-       }
-
        if (family == AF_MPLS) {
                unsigned int maxlabels;
                int i;
@@ -1000,15 +988,6 @@ const char *rt_addr_n2a_r(int af, int len,
                return inet_ntop(af, addr, buf, buflen);
        case AF_MPLS:
                return mpls_ntop(af, addr, buf, buflen);
-       case AF_IPX:
-               return ipx_ntop(af, addr, buf, buflen);
-       case AF_DECnet:
-       {
-               struct dn_naddr dna = { 2, { 0, 0, } };
-
-               memcpy(dna.a_addr, addr, 2);
-               return dnet_ntop(af, &dna, buf, buflen);
-       }
        case AF_PACKET:
                return ll_addr_n2a(addr, len, ARPHRD_VOID, buf, buflen);
        case AF_BRIDGE:
@@ -1050,8 +1029,6 @@ int read_family(const char *name)
                family = AF_INET;
        else if (strcmp(name, "inet6") == 0)
                family = AF_INET6;
-       else if (strcmp(name, "dnet") == 0)
-               family = AF_DECnet;
        else if (strcmp(name, "link") == 0)
                family = AF_PACKET;
        else if (strcmp(name, "ipx") == 0)
@@ -1069,8 +1046,6 @@ const char *family_name(int family)
                return "inet";
        if (family == AF_INET6)
                return "inet6";
-       if (family == AF_DECnet)
-               return "dnet";
        if (family == AF_PACKET)
                return "link";
        if (family == AF_IPX)
index 5132f514b2794ed2a83163168b59990460b409a3..73d37c190fffa638cd973cb00ede24ad2ac22732 100644 (file)
@@ -496,6 +496,8 @@ the following additional arguments are supported:
 ] [
 .BI tos " TOS "
 ] [
+.BI df " DF "
+] [
 .BI flowlabel " FLOWLABEL "
 ] [
 .BI dstport " PORT "
@@ -565,6 +567,18 @@ parameter.
 .BI tos " TOS"
 - specifies the TOS value to use in outgoing packets.
 
+.sp
+.BI df " DF"
+- specifies the usage of the Don't Fragment flag (DF) bit in outgoing packets
+with IPv4 headers. The value
+.B inherit
+causes the bit to be copied from the original IP header. The values
+.B unset
+and
+.B set
+cause the bit to be always unset or always set, respectively. By default, the
+bit is not set.
+
 .sp
 .BI flowlabel " FLOWLABEL"
 - specifies the flow label to use in outgoing packets.
@@ -1166,6 +1180,8 @@ the following additional arguments are supported:
 ] [
 .BI tos " TOS "
 ] [
+.BI df " DF "
+] [
 .BI flowlabel " FLOWLABEL "
 ] [
 .BI dstport " PORT"
@@ -1198,6 +1214,18 @@ ttl. Default option is "0".
 .BI tos " TOS"
 - specifies the TOS value to use in outgoing packets.
 
+.sp
+.BI df " DF"
+- specifies the usage of the Don't Fragment flag (DF) bit in outgoing packets
+with IPv4 headers. The value
+.B inherit
+causes the bit to be copied from the original IP header. The values
+.B unset
+and
+.B set
+cause the bit to be always unset or always set, respectively. By default, the
+bit is not set.
+
 .sp
 .BI flowlabel " FLOWLABEL"
 - specifies the flow label to use in outgoing packets.
index 26dfe0b06c86b968b3a83173a123d0e87e9d68e9..9603ac6e02b812cf461125c5780c08964860d9ee 100644 (file)
@@ -107,7 +107,7 @@ replace " } "
 
 .ti -8
 .IR FAMILY " := [ "
-.BR inet " | " inet6 " | " ipx " | " dnet " | " mpls " | " bridge " | " link " ]"
+.BR inet " | " inet6 " | " mpls " | " bridge " | " link " ]"
 
 .ti -8
 .IR OPTIONS " := " FLAGS " [ "
index 1d358879ec39c0eb9b1a3e8fc70f10b98e90e14e..84ade1104b48a3a6a6b6b8d3c8626d8c5d613fca 100644 (file)
@@ -34,7 +34,7 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels
 \fB\-r\fR[\fIesolve\fR] |
 \fB\-iec\fR |
 \fB\-f\fR[\fIamily\fR] {
-.BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | "
+.BR inet " | " inet6 " | " link " } | "
 \fB-4\fR |
 \fB-6\fR |
 \fB-I\fR |
@@ -94,7 +94,7 @@ Zero (0) means loop until all addresses are removed.
 .TP
 .BR "\-f" , " \-family " <FAMILY>
 Specifies the protocol family to use. The protocol family identifier can be one of
-.BR "inet" , " inet6" , " bridge" , " ipx" , " dnet" , " mpls"
+.BR "inet" , " inet6" , " bridge" ,  " mpls"
 or
 .BR link .
 If this option is not present,
@@ -125,16 +125,6 @@ shortcut for
 shortcut for
 .BR "\-family bridge" .
 
-.TP
-.B \-D
-shortcut for
-.BR "\-family decnet" .
-
-.TP
-.B \-I
-shortcut for
-.BR "\-family ipx" .
-
 .TP
 .B \-M
 shortcut for
index b7abfe1088c2f1f3d9e8660586954cdacb79be2c..069f471791904c99a3f4beda8e664dd412aaf34a 100644 (file)
@@ -1,6 +1,6 @@
 .TH RDMA\-DEV 8 "06 Jul 2017" "iproute2" "Linux"
 .SH NAME
-rdmak-dev \- RDMA device configuration
+rdma-dev \- RDMA device configuration
 .SH SYNOPSIS
 .sp
 .ad l
@@ -22,10 +22,18 @@ rdmak-dev \- RDMA device configuration
 .B rdma dev show
 .RI "[ " DEV " ]"
 
+.ti -8
+.B rdma dev set
+.RI "[ " DEV " ]"
+.BR name
+.BR NEWNAME
+
 .ti -8
 .B rdma dev help
 
 .SH "DESCRIPTION"
+.SS rdma dev set - rename rdma device
+
 .SS rdma dev show - display rdma device attributes
 
 .PP
@@ -45,6 +53,11 @@ rdma dev show mlx5_3
 Shows the state of specified RDMA device.
 .RE
 .PP
+rdma dev set mlx5_3 name rdma_0
+.RS 4
+Renames the mlx5_3 device to rdma_0.
+.RE
+.PP
 
 .SH SEE ALSO
 .BR rdma (8),
index 8be8882592eaa2961c30e84ea6fe3330d693ac4b..adff41e39b006c367331808cc7b6fbba28529d60 100644 (file)
@@ -56,8 +56,9 @@ flower \- flow based traffic control filter
 .IR MASKED_IP_TTL " | { "
 .BR dst_ip " | " src_ip " } "
 .IR PREFIX " | { "
-.BR dst_port " | " src_port " } "
-.IR port_number " } | "
+.BR dst_port " | " src_port " } { "
+.IR port_number " | "
+.IR min_port_number-max_port_number " } | "
 .B tcp_flags
 .IR MASKED_TCP_FLAGS " | "
 .B type
@@ -220,10 +221,12 @@ must be a valid IPv4 or IPv6 address, depending on the \fBprotocol\fR
 option to tc filter, optionally followed by a slash and the prefix length.
 If the prefix is missing, \fBtc\fR assumes a full-length host match.
 .TP
-.BI dst_port " NUMBER"
+.IR \fBdst_port " { "  NUMBER " | " " MIN_VALUE-MAX_VALUE "  }
 .TQ
-.BI src_port " NUMBER"
-Match on layer 4 protocol source or destination port number. Only available for
+.IR \fBsrc_port " { "  NUMBER " | " " MIN_VALUE-MAX_VALUE "  }
+Match on layer 4 protocol source or destination port number. Alternatively, the
+mininum and maximum values can be specified to match on a range of layer 4
+protocol source or destination port numbers. Only available for
 .BR ip_proto " values " udp ", " tcp  " and " sctp
 which have to be specified in beforehand.
 .TP
index f058a05a531716093d5b3d7d6f2fe4d41577078d..1febe62bb3a6cc1e47b9116881d22986dfa16806 100644 (file)
@@ -15,23 +15,28 @@ BYTES ] [
 .B maxrate
 RATE ] [
 .B buckets
-NUMBER ]  [
+NUMBER ] [
+.B orphan_mask
+NUMBER ] [
 .B pacing
 |
 .B nopacing
-]
+] [
+.B ce_threshold
+TIME ]
 
 .SH DESCRIPTION
 FQ (Fair Queue) is a classless packet scheduler meant to be mostly
 used for locally generated traffic.  It is designed to achieve per flow pacing.
 FQ does flow separation, and is able to respect pacing requirements set by TCP stack.
 All packets belonging to a socket are considered as a 'flow'.
-For non local packets (router workload), packet rxhash is used as fallback.
+For non local packets (router workload), packet hash is used as fallback.
 
 An application can specify a maximum pacing rate using the
 .B SO_MAX_PACING_RATE
 setsockopt call.  This packet scheduler adds delay between packets to
-respect rate limitation set by TCP stack.
+respect rate limitation set on each socket. Note that after linux-4.20, linux adopted EDT (Earliest Departure Time)
+and TCP directly sets the appropriate Departure Time for each skb.
 
 Dequeueing happens in a round-robin fashion.
 A special FIFO queue is reserved for high priority packets (
@@ -72,18 +77,28 @@ is ignored only if it is larger than this value.
 The size of the hash table used for flow lookups. Each bucket is assigned a
 red-black tree for efficient collision sorting.
 Default: 1024.
+.SS orphan_mask
+For packets not owned by a socket, fq is able to mask a part of skb->hash
+and reduce number of buckets associated with the traffic. This is a DDOS
+prevention mechanism, and the default is 1023 (meaning no more than 1024 flows
+are allocated for these packets)
 .SS [no]pacing
 Enable or disable flow pacing. Default is enabled.
+.SS ce_threshold
+sets a threshold above which all packets are marked with ECN Congestion
+Experienced. This is useful for DCTCP-style congestion control algorithms that
+require marking at very shallow queueing thresholds.
+
 .SH EXAMPLES
-#tc qdisc add dev eth0 root fq
+#tc qdisc add dev eth0 root est 1sec 4sec fq ce_threshold 4ms
 .br
-#tc -s -d qdisc
+#tc -s -d qdisc sh dev eth0
 .br
-qdisc fq 8003: dev eth0 root refcnt 2 limit 10000p flow_limit 100p buckets 1024 quantum 3028 initial_quantum 15140
- Sent 503727981 bytes 1146972 pkt (dropped 0, overlimits 0 requeues 54452)
- backlog 0b 0p requeues 54452
-  1289 flows (1289 inactive, 0 throttled)
-  0 gc, 31 highprio, 27411 throttled
+qdisc fq 800e: root refcnt 9 limit 10000p flow_limit 1000p buckets 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 low_rate_threshold 550Kbit refill_delay 40.0ms ce_threshold 4.0ms
+ Sent 533368436185 bytes 352296695 pkt (dropped 0, overlimits 0 requeues 1339864)
+ rate 39220Mbit 3238202pps backlog 12417828b 358p requeues 1339864
+  1052 flows (852 inactive, 0 throttled)
+  112 gc, 0 highprio, 212 throttled, 21501 ns latency, 470241 ce_mark
 .br
 .SH SEE ALSO
 .BR tc (8),
index 7738a6cfa8ee0fdcf6a55d4758433ff30f8603ef..60ff4b31e3204cb32fa16c0642b84ffa9bf0af00 100644 (file)
@@ -14,6 +14,7 @@
 static int dev_help(struct rd *rd)
 {
        pr_out("Usage: %s dev show [DEV]\n", rd->filename);
+       pr_out("       %s dev set [DEV] name DEVNAME\n", rd->filename);
        return 0;
 }
 
@@ -258,17 +259,51 @@ static int dev_one_show(struct rd *rd)
        return rd_exec_cmd(rd, cmds, "parameter");
 }
 
+static int dev_set_name(struct rd *rd)
+{
+       uint32_t seq;
+
+       if (rd_no_arg(rd)) {
+               pr_err("Please provide device new name.\n");
+               return -EINVAL;
+       }
+
+       rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET,
+                      &seq, (NLM_F_REQUEST | NLM_F_ACK));
+       mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
+       mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd_argv(rd));
+
+       return rd_send_msg(rd);
+}
+
+static int dev_one_set(struct rd *rd)
+{
+       const struct rd_cmd cmds[] = {
+               { NULL,         dev_help},
+               { "name",       dev_set_name},
+               { 0 }
+       };
+
+       return rd_exec_cmd(rd, cmds, "parameter");
+}
+
 static int dev_show(struct rd *rd)
 {
        return rd_exec_dev(rd, dev_one_show);
 }
 
+static int dev_set(struct rd *rd)
+{
+       return rd_exec_require_dev(rd, dev_one_set);
+}
+
 int cmd_dev(struct rd *rd)
 {
        const struct rd_cmd cmds[] = {
                { NULL,         dev_show },
                { "show",       dev_show },
                { "list",       dev_show },
+               { "set",        dev_set },
                { "help",       dev_help },
                { 0 }
        };
index 05c3c69b07fd42a8aadf084e48d646d0a05b06a3..547bb5749a39f68e7237f976ee57518f3e7aa21d 100644 (file)
@@ -74,6 +74,13 @@ struct rd_cmd {
        int (*func)(struct rd *rd);
 };
 
+/*
+ * Parser interface
+ */
+bool rd_no_arg(struct rd *rd);
+void rd_arg_inc(struct rd *rd);
+
+char *rd_argv(struct rd *rd);
 
 /*
  * Commands interface
@@ -83,11 +90,14 @@ int cmd_link(struct rd *rd);
 int cmd_res(struct rd *rd);
 int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str);
 int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd));
+int rd_exec_require_dev(struct rd *rd, int (*cb)(struct rd *rd));
 int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port);
 void rd_free(struct rd *rd);
 int rd_set_arg_to_devname(struct rd *rd);
 int rd_argc(struct rd *rd);
 
+int strcmpx(const char *str1, const char *str2);
+
 /*
  * Device manipulation
  */
@@ -108,12 +118,14 @@ int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, uint32_t seq);
 void rd_prepare_msg(struct rd *rd, uint32_t cmd, uint32_t *seq, uint16_t flags);
 int rd_dev_init_cb(const struct nlmsghdr *nlh, void *data);
 int rd_attr_cb(const struct nlattr *attr, void *data);
+int rd_attr_check(const struct nlattr *attr, int *typep);
 
 /*
  * Print helpers
  */
 void print_driver_table(struct rd *rd, struct nlattr *tb);
 void newline(struct rd *rd);
+void newline_indent(struct rd *rd);
 #define MAX_LINE_LENGTH 80
 
 #endif /* _RDMA_TOOL_H_ */
index 1a0cf56800d4c54ce31dbef2bb6227ab39e7e04c..61f4aeb1bcf27ca5c345e152d1b8501c7c487310 100644 (file)
@@ -18,14 +18,14 @@ int rd_argc(struct rd *rd)
        return rd->argc;
 }
 
-static char *rd_argv(struct rd *rd)
+char *rd_argv(struct rd *rd)
 {
        if (!rd_argc(rd))
                return NULL;
        return *rd->argv;
 }
 
-static int strcmpx(const char *str1, const char *str2)
+int strcmpx(const char *str1, const char *str2)
 {
        if (strlen(str1) > strlen(str2))
                return -1;
@@ -39,7 +39,7 @@ static bool rd_argv_match(struct rd *rd, const char *pattern)
        return strcmpx(rd_argv(rd), pattern) == 0;
 }
 
-static void rd_arg_inc(struct rd *rd)
+void rd_arg_inc(struct rd *rd)
 {
        if (!rd_argc(rd))
                return;
@@ -47,7 +47,7 @@ static void rd_arg_inc(struct rd *rd)
        rd->argv++;
 }
 
-static bool rd_no_arg(struct rd *rd)
+bool rd_no_arg(struct rd *rd)
 {
        return rd_argc(rd) == 0;
 }
@@ -404,7 +404,7 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
        [RDMA_NLDEV_ATTR_DRIVER_U64] = MNL_TYPE_U64,
 };
 
-static int rd_attr_check(const struct nlattr *attr, int *typep)
+int rd_attr_check(const struct nlattr *attr, int *typep)
 {
        int type;
 
@@ -577,6 +577,16 @@ out:
        return ret;
 }
 
+int rd_exec_require_dev(struct rd *rd, int (*cb)(struct rd *rd))
+{
+       if (rd_no_arg(rd)) {
+               pr_err("Please provide device name.\n");
+               return -EINVAL;
+       }
+
+       return rd_exec_dev(rd, cb);
+}
+
 int rd_exec_cmd(struct rd *rd, const struct rd_cmd *cmds, const char *str)
 {
        const struct rd_cmd *c;
@@ -696,7 +706,7 @@ void newline(struct rd *rd)
                pr_out("\n");
 }
 
-static void newline_indent(struct rd *rd)
+void newline_indent(struct rd *rd)
 {
        newline(rd);
        if (!rd->json_output)
index 65fca04303bad63783f66a4279d3a51ed76a60e6..c563666702b50973703f37c0174bfae3f242fdf3 100644 (file)
@@ -473,24 +473,57 @@ static int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint)
                return -1;
 }
 
+static int flower_port_range_attr_type(__u8 ip_proto, enum flower_endpoint type,
+                                      __be16 *min_port_type,
+                                      __be16 *max_port_type)
+{
+       if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP ||
+           ip_proto == IPPROTO_SCTP) {
+               if (type == FLOWER_ENDPOINT_SRC) {
+                       *min_port_type = TCA_FLOWER_KEY_PORT_SRC_MIN;
+                       *max_port_type = TCA_FLOWER_KEY_PORT_SRC_MAX;
+               } else {
+                       *min_port_type = TCA_FLOWER_KEY_PORT_DST_MIN;
+                       *max_port_type = TCA_FLOWER_KEY_PORT_DST_MAX;
+               }
+       } else {
+               return -1;
+       }
+       return 0;
+}
+
 static int flower_parse_port(char *str, __u8 ip_proto,
                             enum flower_endpoint endpoint,
                             struct nlmsghdr *n)
 {
+       __u16 min, max;
        int ret;
-       int type;
-       __be16 port;
 
-       type = flower_port_attr_type(ip_proto, endpoint);
-       if (type < 0)
-               return -1;
+       ret = sscanf(str, "%hu-%hu", &min, &max);
 
-       ret = get_be16(&port, str, 10);
-       if (ret)
-               return -1;
+       if (ret == 1) {
+               int type;
 
-       addattr16(n, MAX_MSG, type, port);
+               type = flower_port_attr_type(ip_proto, endpoint);
+               if (type < 0)
+                       return -1;
+               addattr16(n, MAX_MSG, type, htons(min));
+       } else if (ret == 2) {
+               __be16 min_port_type, max_port_type;
 
+               if (max <= min) {
+                       fprintf(stderr, "max value should be greater than min value\n");
+                       return -1;
+               }
+               if (flower_port_range_attr_type(ip_proto, endpoint,
+                                               &min_port_type, &max_port_type))
+                       return -1;
+
+               addattr16(n, MAX_MSG, min_port_type, htons(min));
+               addattr16(n, MAX_MSG, max_port_type, htons(max));
+       } else {
+               return -1;
+       }
        return 0;
 }
 
@@ -1490,6 +1523,29 @@ static void flower_print_port(char *name, struct rtattr *attr)
        print_hu(PRINT_ANY, name, namefrm, rta_getattr_be16(attr));
 }
 
+static void flower_print_port_range(char *name, struct rtattr *min_attr,
+                                   struct rtattr *max_attr)
+{
+       if (!min_attr || !max_attr)
+               return;
+
+       if (is_json_context()) {
+               open_json_object(name);
+               print_hu(PRINT_JSON, "start", NULL, rta_getattr_be16(min_attr));
+               print_hu(PRINT_JSON, "end", NULL, rta_getattr_be16(max_attr));
+               close_json_object();
+       } else {
+               SPRINT_BUF(namefrm);
+               SPRINT_BUF(out);
+               size_t done;
+
+               done = sprintf(out, "%u", rta_getattr_be16(min_attr));
+               sprintf(out + done, "-%u", rta_getattr_be16(max_attr));
+               sprintf(namefrm, "\n  %s %%s", name);
+               print_string(PRINT_ANY, name, namefrm, out);
+       }
+}
+
 static void flower_print_tcp_flags(const char *name, struct rtattr *flags_attr,
                                   struct rtattr *mask_attr)
 {
@@ -1678,6 +1734,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
                            struct rtattr *opt, __u32 handle)
 {
        struct rtattr *tb[TCA_FLOWER_MAX + 1];
+       __be16 min_port_type, max_port_type;
        int nl_type, nl_mask_type;
        __be16 eth_type = 0;
        __u8 ip_proto = 0xff;
@@ -1796,6 +1853,16 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
        if (nl_type >= 0)
                flower_print_port("src_port", tb[nl_type]);
 
+       if (!flower_port_range_attr_type(ip_proto, FLOWER_ENDPOINT_DST,
+                                        &min_port_type, &max_port_type))
+               flower_print_port_range("dst_port",
+                                       tb[min_port_type], tb[max_port_type]);
+
+       if (!flower_port_range_attr_type(ip_proto, FLOWER_ENDPOINT_SRC,
+                                        &min_port_type, &max_port_type))
+               flower_print_port_range("src_port",
+                                       tb[min_port_type], tb[max_port_type]);
+
        flower_print_tcp_flags("tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS],
                               tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]);
 
index b269b1338b6d92377645cc65dc542c6a454dc2a6..1353c80c806ba1bea44ce3c066c51166cca480ec 100644 (file)
@@ -188,8 +188,7 @@ static int choke_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        fprintf(f, "limit %up min %up max %up ",
                qopt->limit, qopt->qth_min, qopt->qth_max);
 
-       if (qopt->flags & TC_RED_ECN)
-               fprintf(f, "ecn ");
+       tc_red_print_flags(qopt->flags);
 
        if (show_details) {
                fprintf(f, "ewma %u ", qopt->Wlog);
index f3dbf2ba0c6f520ec1080b90fa4f08c968325102..a4174380d5d49730e1f7b2d9e83d684f852aa3cf 100644 (file)
--- a/tc/q_fq.c
+++ b/tc/q_fq.c
@@ -56,6 +56,7 @@ static void explain(void)
        fprintf(stderr, "              [ [no]pacing ] [ refill_delay TIME ]\n");
        fprintf(stderr, "              [ low_rate_threshold RATE ]\n");
        fprintf(stderr, "              [ orphan_mask MASK]\n");
+       fprintf(stderr, "              [ ce_threshold TIME ]\n");
 }
 
 static unsigned int ilog2(unsigned int val)
@@ -83,6 +84,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        unsigned int defrate;
        unsigned int refill_delay;
        unsigned int orphan_mask;
+       unsigned int ce_threshold;
        bool set_plimit = false;
        bool set_flow_plimit = false;
        bool set_quantum = false;
@@ -92,6 +94,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        bool set_refill_delay = false;
        bool set_orphan_mask = false;
        bool set_low_rate_threshold = false;
+       bool set_ce_threshold = false;
        int pacing = -1;
        struct rtattr *tail;
 
@@ -135,6 +138,13 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                                return -1;
                        }
                        set_low_rate_threshold = true;
+               } else if (strcmp(*argv, "ce_threshold") == 0) {
+                       NEXT_ARG();
+                       if (get_time(&ce_threshold, *argv)) {
+                               fprintf(stderr, "Illegal \"ce_threshold\"\n");
+                               return -1;
+                       }
+                       set_ce_threshold = true;
                } else if (strcmp(*argv, "defrate") == 0) {
                        NEXT_ARG();
                        if (strchr(*argv, '%')) {
@@ -226,6 +236,9 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        if (set_orphan_mask)
                addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
                          &orphan_mask, sizeof(refill_delay));
+       if (set_ce_threshold)
+               addattr_l(n, 1024, TCA_FQ_CE_THRESHOLD,
+                         &ce_threshold, sizeof(ce_threshold));
        addattr_nest_end(n, tail);
        return 0;
 }
@@ -239,6 +252,7 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        unsigned int rate, quantum;
        unsigned int refill_delay;
        unsigned int orphan_mask;
+       unsigned int ce_threshold;
 
        SPRINT_BUF(b1);
 
@@ -310,21 +324,28 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                fprintf(f, "refill_delay %s ", sprint_time(refill_delay, b1));
        }
 
+       if (tb[TCA_FQ_CE_THRESHOLD] &&
+           RTA_PAYLOAD(tb[TCA_FQ_CE_THRESHOLD]) >= sizeof(__u32)) {
+               ce_threshold = rta_getattr_u32(tb[TCA_FQ_CE_THRESHOLD]);
+               if (ce_threshold != ~0U)
+                       fprintf(f, "ce_threshold %s ", sprint_time(ce_threshold, b1));
+       }
+
        return 0;
 }
 
 static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
                           struct rtattr *xstats)
 {
-       struct tc_fq_qd_stats *st;
+       struct tc_fq_qd_stats *st, _st;
 
        if (xstats == NULL)
                return 0;
 
-       if (RTA_PAYLOAD(xstats) < sizeof(*st))
-               return -1;
+       memset(&_st, 0, sizeof(_st));
+       memcpy(&_st, RTA_DATA(xstats), min(RTA_PAYLOAD(xstats), sizeof(*st)));
 
-       st = RTA_DATA(xstats);
+       st = &_st;
 
        fprintf(f, "  %u flows (%u inactive, %u throttled)",
                st->flows, st->inactive_flows, st->throttled_flows);
@@ -343,6 +364,9 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
        if (st->unthrottle_latency_ns)
                fprintf(f, ", %u ns latency", st->unthrottle_latency_ns);
 
+       if (st->ce_mark)
+               fprintf(f, ", %llu ce_mark", st->ce_mark);
+
        if (st->flows_plimit)
                fprintf(f, ", %llu flows_plimit", st->flows_plimit);
 
index e63fac72a883d690762b62d51f6d44b345e384ec..e297b866c76e82bcd7607b91bd27c0b1351c9f52 100644 (file)
 static void explain(void)
 {
        fprintf(stderr, "Usage: tc qdisc { add | replace | change } ... gred setup vqs NUMBER\n");
-       fprintf(stderr, "           default DEFAULT_VQ [ grio ] [ limit BYTES ]\n");
+       fprintf(stderr, "           default DEFAULT_VQ [ grio ] [ limit BYTES ] [ecn] [harddrop]\n");
        fprintf(stderr, "       tc qdisc change ... gred vq VQ [ prio VALUE ] limit BYTES\n");
        fprintf(stderr, "           min BYTES max BYTES avpkt BYTES [ burst PACKETS ]\n");
-       fprintf(stderr, "           [ probability PROBABILITY ] [ bandwidth KBPS ]\n");
+       fprintf(stderr, "           [ probability PROBABILITY ] [ bandwidth KBPS ] [ecn] [harddrop]\n");
 }
 
 static int init_gred(struct qdisc_util *qu, int argc, char **argv,
@@ -87,6 +87,10 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
                                fprintf(stderr, "Illegal \"limit\"\n");
                                return -1;
                        }
+               } else if (strcmp(*argv, "ecn") == 0) {
+                       opt.flags |= TC_RED_ECN;
+               } else if (strcmp(*argv, "harddrop") == 0) {
+                       opt.flags |= TC_RED_HARDDROP;
                } else if (strcmp(*argv, "help") == 0) {
                        explain();
                        return -1;
@@ -117,15 +121,16 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
 */
 static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
 {
+       struct rtattr *tail, *entry, *vqs;
        int ok = 0;
        struct tc_gred_qopt opt = { 0 };
        unsigned int burst = 0;
        unsigned int avpkt = 0;
+       unsigned int flags = 0;
        double probability = 0.02;
        unsigned int rate = 0;
        int parm;
        __u8 sbuf[256];
-       struct rtattr *tail;
        __u32 max_P;
 
        opt.DP = MAX_DPs;
@@ -208,6 +213,10 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
                                return -1;
                        }
                        ok++;
+               } else if (strcmp(*argv, "ecn") == 0) {
+                       flags |= TC_RED_ECN;
+               } else if (strcmp(*argv, "harddrop") == 0) {
+                       flags |= TC_RED_HARDDROP;
                } else if (strcmp(*argv, "help") == 0) {
                        explain();
                        return -1;
@@ -261,22 +270,167 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
        addattr_l(n, 1024, TCA_GRED_STAB, sbuf, 256);
        max_P = probability * pow(2, 32);
        addattr32(n, 1024, TCA_GRED_MAX_P, max_P);
+
+       vqs = addattr_nest(n, 1024, TCA_GRED_VQ_LIST);
+       entry = addattr_nest(n, 1024, TCA_GRED_VQ_ENTRY);
+       addattr32(n, 1024, TCA_GRED_VQ_DP, opt.DP);
+       addattr32(n, 1024, TCA_GRED_VQ_FLAGS, flags);
+       addattr_nest_end(n, entry);
+       addattr_nest_end(n, vqs);
+
        addattr_nest_end(n, tail);
        return 0;
 }
 
+struct tc_gred_info {
+       bool    flags_present;
+       __u64   bytes;
+       __u32   packets;
+       __u32   backlog;
+       __u32   prob_drop;
+       __u32   prob_mark;
+       __u32   forced_drop;
+       __u32   forced_mark;
+       __u32   pdrop;
+       __u32   other;
+       __u32   flags;
+};
+
+static void
+gred_parse_vqs(struct tc_gred_info *info, struct rtattr *vqs)
+{
+       int rem = RTA_PAYLOAD(vqs);
+       unsigned int offset = 0;
+
+       while (rem > offset) {
+               struct rtattr *tb_entry[TCA_GRED_VQ_ENTRY_MAX + 1] = {};
+               struct rtattr *tb[TCA_GRED_VQ_MAX + 1] = {};
+               struct rtattr *entry;
+               unsigned int len;
+               unsigned int dp;
+
+               entry = RTA_DATA(vqs) + offset;
+
+               parse_rtattr(tb_entry, TCA_GRED_VQ_ENTRY_MAX, entry,
+                            rem - offset);
+               len = RTA_LENGTH(RTA_PAYLOAD(entry));
+               offset += len;
+
+               if (!tb_entry[TCA_GRED_VQ_ENTRY]) {
+                       fprintf(stderr,
+                               "ERROR: Failed to parse Virtual Queue entry\n");
+                       continue;
+               }
+
+               parse_rtattr_nested(tb, TCA_GRED_VQ_MAX,
+                                   tb_entry[TCA_GRED_VQ_ENTRY]);
+
+               if (!tb[TCA_GRED_VQ_DP]) {
+                       fprintf(stderr,
+                               "ERROR: Virtual Queue without DP attribute\n");
+                       continue;
+               }
+
+               dp = rta_getattr_u32(tb[TCA_GRED_VQ_DP]);
+
+               if (tb[TCA_GRED_VQ_STAT_BYTES])
+                       info[dp].bytes =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_BYTES]);
+               if (tb[TCA_GRED_VQ_STAT_PACKETS])
+                       info[dp].packets =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PACKETS]);
+               if (tb[TCA_GRED_VQ_STAT_BACKLOG])
+                       info[dp].backlog =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_BACKLOG]);
+               if (tb[TCA_GRED_VQ_STAT_PROB_DROP])
+                       info[dp].prob_drop =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PROB_DROP]);
+               if (tb[TCA_GRED_VQ_STAT_PROB_MARK])
+                       info[dp].prob_mark =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PROB_MARK]);
+               if (tb[TCA_GRED_VQ_STAT_FORCED_DROP])
+                       info[dp].forced_drop =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_FORCED_DROP]);
+               if (tb[TCA_GRED_VQ_STAT_FORCED_MARK])
+                       info[dp].forced_mark =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_FORCED_MARK]);
+               if (tb[TCA_GRED_VQ_STAT_PDROP])
+                       info[dp].pdrop =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PDROP]);
+               if (tb[TCA_GRED_VQ_STAT_OTHER])
+                       info[dp].other =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_STAT_OTHER]);
+               info[dp].flags_present = !!tb[TCA_GRED_VQ_FLAGS];
+               if (tb[TCA_GRED_VQ_FLAGS])
+                       info[dp].flags =
+                               rta_getattr_u32(tb[TCA_GRED_VQ_FLAGS]);
+       }
+}
+
+static void
+gred_print_stats(struct tc_gred_info *info, struct tc_gred_qopt *qopt)
+{
+       __u64 bytes = info ? info->bytes : qopt->bytesin;
+
+       SPRINT_BUF(b1);
+
+       if (!is_json_context())
+               printf("\n  Queue size: ");
+
+       print_uint(PRINT_JSON, "qave", NULL, qopt->qave);
+       print_string(PRINT_FP, NULL, "average %s ",
+                    sprint_size(qopt->qave, b1));
+
+       print_uint(PRINT_JSON, "backlog", NULL, qopt->backlog);
+       print_string(PRINT_FP, NULL, "current %s ",
+                    sprint_size(qopt->backlog, b1));
+
+       if (!is_json_context())
+               printf("\n  Dropped packets: ");
+
+       if (info) {
+               print_uint(PRINT_ANY, "forced_drop", "forced %u ",
+                          info->forced_drop);
+               print_uint(PRINT_ANY, "prob_drop", "early %u ",
+                          info->prob_drop);
+               print_uint(PRINT_ANY, "pdrop", "pdrop %u ", info->pdrop);
+               print_uint(PRINT_ANY, "other", "other %u ", info->other);
+
+               if (!is_json_context())
+                       printf("\n  Marked packets: ");
+               print_uint(PRINT_ANY, "forced_mark", "forced %u ",
+                          info->forced_mark);
+               print_uint(PRINT_ANY, "prob_mark", "early %u ",
+                          info->prob_mark);
+       } else {
+               print_uint(PRINT_ANY, "forced_drop", "forced %u ",
+                          qopt->forced);
+               print_uint(PRINT_ANY, "prob_drop", "early %u ", qopt->early);
+               print_uint(PRINT_ANY, "pdrop", "pdrop %u ", qopt->pdrop);
+               print_uint(PRINT_ANY, "other", "other %u ", qopt->other);
+       }
+
+       if (!is_json_context())
+               printf("\n  Total packets: ");
+
+       print_uint(PRINT_ANY, "packets", "%u ", qopt->packets);
+
+       print_uint(PRINT_JSON, "bytes", NULL, bytes);
+       print_string(PRINT_FP, NULL, "(%s) ", sprint_size(bytes, b1));
+}
+
 static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 {
+       struct tc_gred_info infos[MAX_DPs] = {};
        struct rtattr *tb[TCA_GRED_MAX + 1];
        struct tc_gred_sopt *sopt;
        struct tc_gred_qopt *qopt;
+       bool vq_info = false;
        __u32 *max_p = NULL;
        __u32 *limit = NULL;
        unsigned int i;
 
        SPRINT_BUF(b1);
-       SPRINT_BUF(b2);
-       SPRINT_BUF(b3);
 
        if (opt == NULL)
                return 0;
@@ -302,47 +456,69 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                return -1;
        }
 
-/* Bad hack! should really return a proper message as shown above*/
+       if (tb[TCA_GRED_VQ_LIST]) {
+               gred_parse_vqs(infos, tb[TCA_GRED_VQ_LIST]);
+               vq_info = true;
+       }
 
-       fprintf(f, "vqs %u default %u %s",
-               sopt->DPs,
-               sopt->def_DP,
-               sopt->grio ? "grio " : "");
+       print_uint(PRINT_ANY, "dp_cnt", "vqs %u ", sopt->DPs);
+       print_uint(PRINT_ANY, "dp_default", "default %u ", sopt->def_DP);
 
-       if (limit)
-               fprintf(f, "limit %s ",
-                       sprint_size(*limit, b1));
+       if (sopt->grio)
+               print_bool(PRINT_ANY, "grio", "grio ", true);
+       else
+               print_bool(PRINT_ANY, "grio", NULL, false);
 
+       if (limit) {
+               print_uint(PRINT_JSON, "limit", NULL, *limit);
+               print_string(PRINT_FP, NULL, "limit %s ",
+                            sprint_size(*limit, b1));
+       }
+
+       tc_red_print_flags(sopt->flags);
+
+       open_json_array(PRINT_JSON, "vqs");
        for (i = 0; i < MAX_DPs; i++, qopt++) {
-               if (qopt->DP >= MAX_DPs) continue;
-               fprintf(f, "\n vq %u prio %hhu limit %s min %s max %s ",
-                       qopt->DP,
-                       qopt->prio,
-                       sprint_size(qopt->limit, b1),
-                       sprint_size(qopt->qth_min, b2),
-                       sprint_size(qopt->qth_max, b3));
+               if (qopt->DP >= MAX_DPs)
+                       continue;
+
+               open_json_object(NULL);
+
+               print_uint(PRINT_ANY, "vq", "\n vq %u ", qopt->DP);
+               print_hhu(PRINT_ANY, "prio", "prio %hhu ", qopt->prio);
+
+               print_uint(PRINT_JSON, "limit", NULL, qopt->limit);
+               print_string(PRINT_FP, NULL, "limit %s ",
+                            sprint_size(qopt->limit, b1));
+
+               print_uint(PRINT_JSON, "min", NULL, qopt->qth_min);
+               print_string(PRINT_FP, NULL, "min %s ",
+                            sprint_size(qopt->qth_min, b1));
+
+               print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
+               print_string(PRINT_FP, NULL, "max %s ",
+                            sprint_size(qopt->qth_max, b1));
+
+               if (infos[i].flags_present)
+                       tc_red_print_flags(infos[i].flags);
+
                if (show_details) {
-                       fprintf(f, "ewma %u ", qopt->Wlog);
+                       print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
                        if (max_p)
-                               fprintf(f, "probability %lg ", max_p[i] / pow(2, 32));
+                               print_float(PRINT_ANY, "probability",
+                                           "probability %lg ",
+                                           max_p[i] / pow(2, 32));
                        else
-                               fprintf(f, "Plog %u ", qopt->Plog);
-                       fprintf(f, "Scell_log %u ", qopt->Scell_log);
-               }
-               if (show_stats) {
-                       fprintf(f, "\n  Queue size: average %s current %s ",
-                               sprint_size(qopt->qave, b1),
-                               sprint_size(qopt->backlog, b2));
-                       fprintf(f, "\n  Dropped packets: forced %u early %u pdrop %u other %u ",
-                               qopt->forced,
-                               qopt->early,
-                               qopt->pdrop,
-                               qopt->other);
-                       fprintf(f, "\n  Total packets: %u (%s) ",
-                               qopt->packets,
-                               sprint_size(qopt->bytesin, b1));
+                               print_uint(PRINT_ANY, "Plog", "Plog %u ",
+                                          qopt->Plog);
+                       print_uint(PRINT_ANY, "Scell_log", "Scell_log %u ",
+                                  qopt->Scell_log);
                }
+               if (show_stats)
+                       gred_print_stats(vq_info ? &infos[i] : NULL, qopt);
+               close_json_object();
        }
+       close_json_array(PRINT_JSON, "vqs");
        return 0;
 }
 
index 49fd4ac8051309189526a48d5c008a83687bfa90..3b3a1204198979d2392ba344ea3c7a5584441064 100644 (file)
@@ -189,18 +189,8 @@ static int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
        print_string(PRINT_FP, NULL, "max %s ", sprint_size(qopt->qth_max, b3));
 
-       if (qopt->flags & TC_RED_ECN)
-               print_bool(PRINT_ANY, "ecn", "ecn ", true);
-       else
-               print_bool(PRINT_ANY, "ecn", NULL, false);
-       if (qopt->flags & TC_RED_HARDDROP)
-               print_bool(PRINT_ANY, "harddrop", "harddrop ", true);
-       else
-               print_bool(PRINT_ANY, "harddrop", NULL, false);
-       if (qopt->flags & TC_RED_ADAPTATIVE)
-               print_bool(PRINT_ANY, "adaptive", "adaptive ", true);
-       else
-               print_bool(PRINT_ANY, "adaptive", NULL, false);
+       tc_red_print_flags(qopt->flags);
+
        if (show_details) {
                print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
                if (max_P)
index 6a1d853b7c9351534836f20f1d2c86e47369d9e1..eee31ec54d331976abcda8d7b2b995aa43794f73 100644 (file)
@@ -235,8 +235,7 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                        sprint_size(qopt_ext->qth_min, b2),
                        sprint_size(qopt_ext->qth_max, b3),
                        qopt_ext->max_P / pow(2, 32));
-               if (qopt_ext->flags & TC_RED_ECN)
-                       fprintf(f, "ecn ");
+               tc_red_print_flags(qopt_ext->flags);
                if (show_stats) {
                        fprintf(f, "\n prob_mark %u prob_mark_head %u prob_drop %u",
                                qopt_ext->stats.prob_mark,
index 178fe088f73260711e5ed1e9bc31644334918b59..3ce3ca4287d3f6441740af34e9fb55d1d64c2baf 100644 (file)
@@ -20,7 +20,9 @@
 #include <arpa/inet.h>
 #include <string.h>
 
+#include "utils.h"
 #include "tc_core.h"
+#include "tc_util.h"
 #include "tc_red.h"
 
 /*
@@ -97,3 +99,21 @@ int tc_red_eval_idle_damping(int Wlog, unsigned int avpkt, unsigned int bps, __u
        sbuf[255] = 31;
        return clog;
 }
+
+void tc_red_print_flags(__u32 flags)
+{
+       if (flags & TC_RED_ECN)
+               print_bool(PRINT_ANY, "ecn", "ecn ", true);
+       else
+               print_bool(PRINT_ANY, "ecn", NULL, false);
+
+       if (flags & TC_RED_HARDDROP)
+               print_bool(PRINT_ANY, "harddrop", "harddrop ", true);
+       else
+               print_bool(PRINT_ANY, "harddrop", NULL, false);
+
+       if (flags & TC_RED_ADAPTATIVE)
+               print_bool(PRINT_ANY, "adaptive", "adaptive ", true);
+       else
+               print_bool(PRINT_ANY, "adaptive", NULL, false);
+}
index 6c6e6b039732729541c1eb1666256e47245b6484..3882c8310d76cd5576d2c4d722a9efc87f262470 100644 (file)
@@ -6,5 +6,6 @@ int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob);
 int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt);
 int tc_red_eval_idle_damping(int wlog, unsigned avpkt, unsigned bandwidth,
                             __u8 *sbuf);
+void tc_red_print_flags(__u32 flags);
 
 #endif