]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - tc/tc_util.c
lib: introduce print_nl
[mirror_iproute2.git] / tc / tc_util.c
index cd7b40b0afe48189abbf6dedc08d11ec45afc016..d7578528a31b1932bab12d793ac1798fef4ac13f 100644 (file)
@@ -13,7 +13,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <syslog.h>
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/param.h>
@@ -82,7 +81,7 @@ int get_qdisc_handle(__u32 *h, const char *str)
        if (strcmp(str, "none") == 0)
                goto ok;
        maj = strtoul(str, &p, 16);
-       if (p == str)
+       if (p == str || maj >= (1 << 16))
                return -1;
        maj <<= 16;
        if (*p != ':' && *p != 0)
@@ -191,6 +190,69 @@ static const struct rate_suffix {
        { NULL }
 };
 
+int parse_percent_rate(char *rate, const char *str, const char *dev)
+{
+       long dev_mbit;
+       int ret;
+       double perc, rate_mbit;
+       char *str_perc;
+
+       if (!dev[0]) {
+               fprintf(stderr, "No device specified; specify device to rate limit by percentage\n");
+               return -1;
+       }
+
+       if (read_prop(dev, "speed", &dev_mbit))
+               return -1;
+
+       ret = sscanf(str, "%m[0-9.%]", &str_perc);
+       if (ret != 1)
+               goto malf;
+
+       if (parse_percent(&perc, str_perc))
+               goto malf;
+
+       free(str_perc);
+
+       if (perc > 1.0 || perc < 0.0) {
+               fprintf(stderr, "Invalid rate specified; should be between [0,100]%% but is %s\n", str);
+               return -1;
+       }
+
+       rate_mbit = perc * dev_mbit;
+
+       ret = snprintf(rate, 20, "%lf", rate_mbit);
+       if (ret <= 0 || ret >= 20) {
+               fprintf(stderr, "Unable to parse calculated rate\n");
+               return -1;
+       }
+
+       return 0;
+
+malf:
+       fprintf(stderr, "Specified rate value could not be read or is malformed\n");
+       return -1;
+}
+
+int get_percent_rate(unsigned int *rate, const char *str, const char *dev)
+{
+       char r_str[20];
+
+       if (parse_percent_rate(r_str, str, dev))
+               return -1;
+
+       return get_rate(rate, r_str);
+}
+
+int get_percent_rate64(__u64 *rate, const char *str, const char *dev)
+{
+       char r_str[20];
+
+       if (parse_percent_rate(r_str, str, dev))
+               return -1;
+
+       return get_rate64(rate, r_str);
+}
 
 int get_rate(unsigned int *rate, const char *str)
 {
@@ -382,6 +444,17 @@ int get_size_and_cell(unsigned int *size, int *cell_log, char *str)
        return 0;
 }
 
+void print_devname(enum output_type type, int ifindex)
+{
+       const char *ifname = ll_index_to_name(ifindex);
+
+       if (!is_json_context())
+               printf("dev ");
+
+       print_color_string(type, COLOR_IFNAME,
+                          "dev", "%s ", ifname);
+}
+
 void print_size(char *buf, int len, __u32 sz)
 {
        double tmp = sz;
@@ -411,26 +484,31 @@ char *sprint_qdisc_handle(__u32 h, char *buf)
        return buf;
 }
 
-char *action_n2a(int action, char *buf, int len)
+static const char *action_n2a(int action)
 {
+       static char buf[64];
+
+       if (TC_ACT_EXT_CMP(action, TC_ACT_GOTO_CHAIN))
+               return "goto";
+       if (TC_ACT_EXT_CMP(action, TC_ACT_JUMP))
+               return "jump";
        switch (action) {
-       case -1:
+       case TC_ACT_UNSPEC:
                return "continue";
-               break;
        case TC_ACT_OK:
                return "pass";
-               break;
        case TC_ACT_SHOT:
                return "drop";
-               break;
        case TC_ACT_RECLASSIFY:
                return "reclassify";
        case TC_ACT_PIPE:
                return "pipe";
        case TC_ACT_STOLEN:
                return "stolen";
+       case TC_ACT_TRAP:
+               return "trap";
        default:
-               snprintf(buf, len, "%d", action);
+               snprintf(buf, 64, "%d", action);
                return buf;
        }
 }
@@ -459,22 +537,207 @@ int action_a2n(char *arg, int *result, bool allow_num)
                {"ok", TC_ACT_OK},
                {"reclassify", TC_ACT_RECLASSIFY},
                {"pipe", TC_ACT_PIPE},
+               {"goto", TC_ACT_GOTO_CHAIN},
+               {"jump", TC_ACT_JUMP},
+               {"trap", TC_ACT_TRAP},
                { NULL },
        }, *iter;
 
        for (iter = a2n; iter->a; iter++) {
                if (matches(arg, iter->a) != 0)
                        continue;
-               *result = iter->n;
-               return 0;
+               n = iter->n;
+               goto out_ok;
        }
        if (!allow_num || sscanf(arg, "%d%c", &n, &dummy) != 1)
                return -1;
 
-       *result = n;
+out_ok:
+       if (result)
+               *result = n;
        return 0;
 }
 
+static int __parse_action_control(int *argc_p, char ***argv_p, int *result_p,
+                                 bool allow_num, bool ignore_a2n_miss)
+{
+       int argc = *argc_p;
+       char **argv = *argv_p;
+       int result;
+
+       if (!argc)
+               return -1;
+       if (action_a2n(*argv, &result, allow_num) == -1) {
+               if (!ignore_a2n_miss)
+                       fprintf(stderr, "Bad action type %s\n", *argv);
+               return -1;
+       }
+       if (result == TC_ACT_GOTO_CHAIN) {
+               __u32 chain_index;
+
+               NEXT_ARG();
+               if (matches(*argv, "chain") != 0) {
+                       fprintf(stderr, "\"chain index\" expected\n");
+                       return -1;
+               }
+               NEXT_ARG();
+               if (get_u32(&chain_index, *argv, 10) ||
+                   chain_index > TC_ACT_EXT_VAL_MASK) {
+                       fprintf(stderr, "Illegal \"chain index\"\n");
+                       return -1;
+               }
+               result |= chain_index;
+       }
+       if (result == TC_ACT_JUMP) {
+               __u32 jump_cnt = 0;
+
+               NEXT_ARG();
+               if (get_u32(&jump_cnt, *argv, 10) ||
+                   jump_cnt > TC_ACT_EXT_VAL_MASK) {
+                       fprintf(stderr, "Invalid \"jump count\" (%s)\n", *argv);
+                       return -1;
+               }
+               result |= jump_cnt;
+       }
+       NEXT_ARG_FWD();
+       *argc_p = argc;
+       *argv_p = argv;
+       *result_p = result;
+       return 0;
+}
+
+/* Parse action control including possible options.
+ *
+ * Parameters:
+ * @argc_p - pointer to argc to parse
+ * @argv_p - pointer to argv to parse
+ * @result_p - pointer to output variable
+ * @allow_num - whether action may be in numeric format already
+ *
+ * In error case, returns -1 and does not touch @result_1p. Otherwise returns 0.
+ */
+int parse_action_control(int *argc_p, char ***argv_p,
+                        int *result_p, bool allow_num)
+{
+       return __parse_action_control(argc_p, argv_p, result_p,
+                                     allow_num, false);
+}
+
+/* Parse action control including possible options.
+ *
+ * Parameters:
+ * @argc_p - pointer to argc to parse
+ * @argv_p - pointer to argv to parse
+ * @result_p - pointer to output variable
+ * @allow_num - whether action may be in numeric format already
+ * @default_result - set as a result in case of parsing error
+ *
+ * In case there is an error during parsing, the default result is used.
+ */
+void parse_action_control_dflt(int *argc_p, char ***argv_p,
+                              int *result_p, bool allow_num,
+                              int default_result)
+{
+       if (__parse_action_control(argc_p, argv_p, result_p, allow_num, true))
+               *result_p = default_result;
+}
+
+static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p,
+                                            int *result1_p, int *result2_p,
+                                            bool allow_num)
+{
+       int argc = *argc_p;
+       char **argv = *argv_p;
+       int result1 = -1, result2;
+       int *result_p = &result1;
+       int ok = 0;
+       int ret;
+
+       while (argc > 0) {
+               switch (ok) {
+               case 1:
+                       if (strcmp(*argv, "/") != 0)
+                               goto out;
+                       result_p = &result2;
+                       NEXT_ARG();
+                       /* fall-through */
+               case 0: /* fall-through */
+               case 2:
+                       ret = parse_action_control(&argc, &argv,
+                                                  result_p, allow_num);
+                       if (ret)
+                               return ret;
+                       ok++;
+                       break;
+               default:
+                       goto out;
+               }
+       }
+out:
+       *result1_p = result1;
+       if (ok == 2)
+               *result2_p = result2;
+       *argc_p = argc;
+       *argv_p = argv;
+       return 0;
+}
+
+/* Parse action control with slash including possible options.
+ *
+ * Parameters:
+ * @argc_p - pointer to argc to parse
+ * @argv_p - pointer to argv to parse
+ * @result1_p - pointer to the first (before slash) output variable
+ * @result2_p - pointer to the second (after slash) output variable
+ * @allow_num - whether action may be in numeric format already
+ *
+ * In error case, returns -1 and does not touch @result*. Otherwise returns 0.
+ */
+int parse_action_control_slash(int *argc_p, char ***argv_p,
+                              int *result1_p, int *result2_p, bool allow_num)
+{
+       int result1, result2, argc = *argc_p;
+       char **argv = *argv_p;
+       char *p = strchr(*argv, '/');
+
+       if (!p)
+               return parse_action_control_slash_spaces(argc_p, argv_p,
+                                                        result1_p, result2_p,
+                                                        allow_num);
+       *p = 0;
+       if (action_a2n(*argv, &result1, allow_num)) {
+               *p = '/';
+               return -1;
+       }
+
+       *p = '/';
+       if (action_a2n(p + 1, &result2, allow_num))
+               return -1;
+
+       *result1_p = result1;
+       *result2_p = result2;
+       NEXT_ARG_FWD();
+       *argc_p = argc;
+       *argv_p = argv;
+       return 0;
+}
+
+void print_action_control(FILE *f, const char *prefix,
+                         int action, const char *suffix)
+{
+       print_string(PRINT_FP, NULL, "%s", prefix);
+       open_json_object("control_action");
+       print_string(PRINT_ANY, "type", "%s", action_n2a(action));
+       if (TC_ACT_EXT_CMP(action, TC_ACT_GOTO_CHAIN))
+               print_uint(PRINT_ANY, "chain", " chain %u",
+                          action & TC_ACT_EXT_VAL_MASK);
+       if (TC_ACT_EXT_CMP(action, TC_ACT_JUMP))
+               print_uint(PRINT_ANY, "jump", " %u",
+                          action & TC_ACT_EXT_VAL_MASK);
+       close_json_object();
+       print_string(PRINT_FP, NULL, "%s", suffix);
+}
+
 int get_linklayer(unsigned int *val, const char *arg)
 {
        int res;
@@ -520,12 +783,21 @@ void print_tm(FILE *f, const struct tcf_t *tm)
 {
        int hz = get_user_hz();
 
-       if (tm->install != 0)
-               fprintf(f, " installed %u sec", (unsigned int)(tm->install/hz));
-       if (tm->lastuse != 0)
-               fprintf(f, " used %u sec", (unsigned int)(tm->lastuse/hz));
-       if (tm->expires != 0)
-               fprintf(f, " expires %u sec", (unsigned int)(tm->expires/hz));
+       if (tm->install != 0) {
+               print_uint(PRINT_JSON, "installed", NULL, tm->install);
+               print_uint(PRINT_FP, NULL, " installed %u sec",
+                          (unsigned int)(tm->install/hz));
+       }
+       if (tm->lastuse != 0) {
+               print_uint(PRINT_JSON, "last_used", NULL, tm->lastuse);
+               print_uint(PRINT_FP, NULL, " used %u sec",
+                          (unsigned int)(tm->lastuse/hz));
+       }
+       if (tm->expires != 0) {
+               print_uint(PRINT_JSON, "expires", NULL, tm->expires);
+               print_uint(PRINT_FP, NULL, " expires %u sec",
+                          (unsigned int)(tm->expires/hz));
+       }
 }
 
 void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats)
@@ -539,16 +811,19 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat
                struct gnet_stats_basic bs = {0};
 
                memcpy(&bs, RTA_DATA(tbs[TCA_STATS_BASIC]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC]), sizeof(bs)));
-               fprintf(fp, "%sSent %llu bytes %u pkt",
-                       prefix, (unsigned long long) bs.bytes, bs.packets);
+               print_string(PRINT_FP, NULL, "%s", prefix);
+               print_lluint(PRINT_ANY, "bytes", "Sent %llu bytes", bs.bytes);
+               print_uint(PRINT_ANY, "packets", " %u pkt", bs.packets);
        }
 
        if (tbs[TCA_STATS_QUEUE]) {
                struct gnet_stats_queue q = {0};
 
                memcpy(&q, RTA_DATA(tbs[TCA_STATS_QUEUE]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_QUEUE]), sizeof(q)));
-               fprintf(fp, " (dropped %u, overlimits %u requeues %u) ",
-                       q.drops, q.overlimits, q.requeues);
+               print_uint(PRINT_ANY, "drops", " (dropped %u", q.drops);
+               print_uint(PRINT_ANY, "overlimits", ", overlimits %u",
+                          q.overlimits);
+               print_uint(PRINT_ANY, "requeues", " requeues %u) ", q.requeues);
        }
 
        if (tbs[TCA_STATS_RATE_EST64]) {
@@ -557,15 +832,21 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat
                memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST64]),
                       MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST64]),
                           sizeof(re)));
-               fprintf(fp, "\n%srate %s %llupps ",
-                       prefix, sprint_rate(re.bps, b1), re.pps);
+               print_string(PRINT_FP, NULL, "\n%s", prefix);
+               print_lluint(PRINT_JSON, "rate", NULL, re.bps);
+               print_string(PRINT_FP, NULL, "rate %s",
+                            sprint_rate(re.bps, b1));
+               print_lluint(PRINT_ANY, "pps", " %llupps", re.pps);
        } else if (tbs[TCA_STATS_RATE_EST]) {
                struct gnet_stats_rate_est re = {0};
 
                memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST]),
                       MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST]), sizeof(re)));
-               fprintf(fp, "\n%srate %s %upps ",
-                       prefix, sprint_rate(re.bps, b1), re.pps);
+               print_string(PRINT_FP, NULL, "\n%s", prefix);
+               print_uint(PRINT_JSON, "rate", NULL, re.bps);
+               print_string(PRINT_FP, NULL, "rate %s",
+                            sprint_rate(re.bps, b1));
+               print_uint(PRINT_ANY, "pps", " %upps", re.pps);
        }
 
        if (tbs[TCA_STATS_QUEUE]) {
@@ -573,9 +854,12 @@ 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])
-                       fprintf(fp, "\n%s", prefix);
-               fprintf(fp, "backlog %s %up requeues %u ",
-                       sprint_size(q.backlog, b1), q.qlen, q.requeues);
+                       print_string(PRINT_FP, NULL, "\n%s", prefix);
+               print_uint(PRINT_JSON, "backlog", NULL, q.backlog);
+               print_string(PRINT_FP, NULL, "backlog %s",
+                            sprint_size(q.backlog, b1));
+               print_uint(PRINT_ANY, "qlen", " %up", q.qlen);
+               print_uint(PRINT_FP, NULL, " requeues %u", q.requeues);
        }
 
        if (xstats)