diff --git a/man/man8/tc-actions.8 b/man/man8/tc-actions.8 index bee59f72..21795193 100644 --- a/man/man8/tc-actions.8 +++ b/man/man8/tc-actions.8 @@ -49,6 +49,8 @@ actions \- independently defined actions in tc ] [ .I FLAGS ] [ +.I HWSTATSSPEC +] [ .I CONTROL ] @@ -77,6 +79,12 @@ ACTNAME := .I no_percpu +.I HWSTATSSPEC +:= +.BR hw_stats " {" +.IR immediate " | " delayed " | " disabled +.R } + .I ACTDETAIL := .I ACTNAME ACTPARAMS @@ -200,6 +208,29 @@ which indicates that action is expected to have minimal software data-path traffic and doesn't need to allocate stat counters with percpu allocator. This option is intended to be used by hardware-offloaded actions. +.TP +.BI hw_stats " HW_STATS" +Specifies the type of HW stats of new action. If omitted, any stats counter type +is going to be used, according to driver and its resources. +The +.I HW_STATS +indicates the type. Any of the following are valid: +.RS +.TP +.B immediate +Means that in dump, user gets the current HW stats state from the device +queried at the dump time. +.TP +.B delayed +Means that in dump, user gets HW stats that might be out of date for +some time, maybe couple of seconds. This is the case when driver polls +stats updates periodically or when it gets async stats update +from the device. +.TP +.B disabled +No HW stats are going to be available in dump. +.RE + .TP .BI since " MSTIME" When dumping large number of actions, a millisecond time-filter can be diff --git a/tc/m_action.c b/tc/m_action.c index 4da810c8..58ae1846 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -51,8 +51,9 @@ static void act_usage(void) " FL := ls | list | flush | \n" " ACTNAMESPEC := action \n" " ACTISPEC := \n" - " ACTSPEC := action [INDEXSPEC]\n" + " ACTSPEC := action [INDEXSPEC] [HWSTATSSPEC]\n" " INDEXSPEC := index <32 bit indexvalue>\n" + " HWSTATSSPEC := hw_stats [ immediate | delayed | disabled ]\n" " ACTDETAIL := \n" " Example ACTNAME is gact, mirred, bpf, etc\n" " Each action has its own parameters (ACTPARAMS)\n" @@ -149,6 +150,59 @@ new_cmd(char **argv) (matches(*argv, "add") == 0); } +static const struct hw_stats_type_item { + const char *str; + __u8 type; +} hw_stats_type_items[] = { + { "immediate", TCA_ACT_HW_STATS_TYPE_IMMEDIATE }, + { "delayed", TCA_ACT_HW_STATS_TYPE_DELAYED }, + { "disabled", 0 }, /* no bit set */ +}; + +static void print_hw_stats(const struct rtattr *arg) +{ + struct nla_bitfield32 *hw_stats_type_bf = RTA_DATA(arg); + __u8 hw_stats_type; + int i; + + hw_stats_type = hw_stats_type_bf->value & hw_stats_type_bf->selector; + print_string(PRINT_FP, NULL, "\t", NULL); + open_json_array(PRINT_ANY, "hw_stats"); + + for (i = 0; i < ARRAY_SIZE(hw_stats_type_items); i++) { + const struct hw_stats_type_item *item; + + item = &hw_stats_type_items[i]; + if ((!hw_stats_type && !item->type) || + hw_stats_type & item->type) + print_string(PRINT_ANY, NULL, " %s", item->str); + } + close_json_array(PRINT_JSON, NULL); +} + +static int parse_hw_stats(const char *str, struct nlmsghdr *n) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_stats_type_items); i++) { + const struct hw_stats_type_item *item; + + item = &hw_stats_type_items[i]; + if (matches(str, item->str) == 0) { + struct nla_bitfield32 hw_stats_type_bf = { + .value = item->type, + .selector = item->type + }; + + addattr_l(n, MAX_MSG, TCA_ACT_HW_STATS_TYPE, + &hw_stats_type_bf, sizeof(hw_stats_type_bf)); + return 0; + } + + } + return -1; +} + int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { int argc = *argc_p; @@ -250,6 +304,14 @@ done0: addattr_l(n, MAX_MSG, TCA_ACT_COOKIE, &act_ck, act_ck_len); + if (*argv && matches(*argv, "hw_stats") == 0) { + NEXT_ARG(); + ret = parse_hw_stats(*argv, n); + if (ret < 0) + invarg("value is invalid\n", *argv); + NEXT_ARG_FWD(); + } + if (*argv && strcmp(*argv, "no_percpu") == 0) { struct nla_bitfield32 flags = { TCA_ACT_FLAGS_NO_PERCPU_STATS, @@ -337,6 +399,8 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg) TCA_ACT_FLAGS_NO_PERCPU_STATS); print_string(PRINT_FP, NULL, "%s", _SL_); } + if (tb[TCA_ACT_HW_STATS_TYPE]) + print_hw_stats(tb[TCA_ACT_HW_STATS_TYPE]); return 0; }