aboutsummaryrefslogtreecommitdiffstats
path: root/tc/tc_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'tc/tc_util.c')
-rw-r--r--tc/tc_util.c307
1 files changed, 253 insertions, 54 deletions
diff --git a/tc/tc_util.c b/tc/tc_util.c
index 4764ecce..b39e5508 100644
--- a/tc/tc_util.c
+++ b/tc/tc_util.c
@@ -32,7 +32,7 @@
#define LIBDIR "/usr/lib"
#endif
-static struct db_names *cls_names = NULL;
+static struct db_names *cls_names;
#define NAMES_DB "/etc/iproute2/tc_cls"
@@ -82,10 +82,10 @@ 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)
+ if (*p != ':' && *p != 0)
return -1;
ok:
*h = maj;
@@ -192,7 +192,7 @@ static const struct rate_suffix {
};
-int get_rate(unsigned *rate, const char *str)
+int get_rate(unsigned int *rate, const char *str)
{
char *p;
double bps = strtod(str, &p);
@@ -266,13 +266,13 @@ void print_rate(char *buf, int len, __u64 rate)
snprintf(buf, len, "%.0f%s%sbit", (double)rate, units[i], str);
}
-char * sprint_rate(__u64 rate, char *buf)
+char *sprint_rate(__u64 rate, char *buf)
{
print_rate(buf, SPRINT_BSIZE-1, rate);
return buf;
}
-int get_time(unsigned *time, const char *str)
+int get_time(unsigned int *time, const char *str)
{
double t;
char *p;
@@ -282,13 +282,13 @@ int get_time(unsigned *time, const char *str)
return -1;
if (*p) {
- if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
- strcasecmp(p, "secs")==0)
+ if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec") == 0 ||
+ strcasecmp(p, "secs") == 0)
t *= TIME_UNITS_PER_SEC;
- else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
+ else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec") == 0 ||
strcasecmp(p, "msecs") == 0)
t *= TIME_UNITS_PER_SEC/1000;
- else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
+ else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec") == 0 ||
strcasecmp(p, "usecs") == 0)
t *= TIME_UNITS_PER_SEC/1000000;
else
@@ -312,18 +312,18 @@ void print_time(char *buf, int len, __u32 time)
snprintf(buf, len, "%uus", time);
}
-char * sprint_time(__u32 time, char *buf)
+char *sprint_time(__u32 time, char *buf)
{
print_time(buf, SPRINT_BSIZE-1, time);
return buf;
}
-char * sprint_ticks(__u32 ticks, char *buf)
+char *sprint_ticks(__u32 ticks, char *buf)
{
return sprint_time(tc_core_tick2time(ticks), buf);
}
-int get_size(unsigned *size, const char *str)
+int get_size(unsigned int *size, const char *str)
{
double sz;
char *p;
@@ -333,13 +333,13 @@ int get_size(unsigned *size, const char *str)
return -1;
if (*p) {
- if (strcasecmp(p, "kb") == 0 || strcasecmp(p, "k")==0)
+ if (strcasecmp(p, "kb") == 0 || strcasecmp(p, "k") == 0)
sz *= 1024;
- else if (strcasecmp(p, "gb") == 0 || strcasecmp(p, "g")==0)
+ else if (strcasecmp(p, "gb") == 0 || strcasecmp(p, "g") == 0)
sz *= 1024*1024*1024;
else if (strcasecmp(p, "gbit") == 0)
sz *= 1024*1024*1024/8;
- else if (strcasecmp(p, "mb") == 0 || strcasecmp(p, "m")==0)
+ else if (strcasecmp(p, "mb") == 0 || strcasecmp(p, "m") == 0)
sz *= 1024*1024;
else if (strcasecmp(p, "mbit") == 0)
sz *= 1024*1024/8;
@@ -353,9 +353,9 @@ int get_size(unsigned *size, const char *str)
return 0;
}
-int get_size_and_cell(unsigned *size, int *cell_log, char *str)
+int get_size_and_cell(unsigned int *size, int *cell_log, char *str)
{
- char * slash = strchr(str, '/');
+ char *slash = strchr(str, '/');
if (slash)
*slash = 0;
@@ -371,7 +371,7 @@ int get_size_and_cell(unsigned *size, int *cell_log, char *str)
return -1;
*slash = '/';
- for (i=0; i<32; i++) {
+ for (i = 0; i < 32; i++) {
if ((1<<i) == cell) {
*cell_log = i;
return 0;
@@ -394,7 +394,7 @@ void print_size(char *buf, int len, __u32 sz)
snprintf(buf, len, "%ub", sz);
}
-char * sprint_size(__u32 size, char *buf)
+char *sprint_size(__u32 size, char *buf)
{
print_size(buf, SPRINT_BSIZE-1, size);
return buf;
@@ -405,62 +405,258 @@ void print_qdisc_handle(char *buf, int len, __u32 h)
snprintf(buf, len, "%x:", TC_H_MAJ(h)>>16);
}
-char * sprint_qdisc_handle(__u32 h, char *buf)
+char *sprint_qdisc_handle(__u32 h, char *buf)
{
print_qdisc_handle(buf, SPRINT_BSIZE-1, h);
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;
}
}
-int action_a2n(char *arg, int *result)
+/* Convert action branch name into numeric format.
+ *
+ * Parameters:
+ * @arg - string to parse
+ * @result - pointer to output variable
+ * @allow_num - whether @arg may be in numeric format already
+ *
+ * In error case, returns -1 and does not touch @result. Otherwise returns 0.
+ */
+static int action_a2n(char *arg, int *result, bool allow_num)
{
- int res;
+ int n;
+ char dummy;
+ struct {
+ const char *a;
+ int n;
+ } a2n[] = {
+ {"continue", TC_ACT_UNSPEC},
+ {"drop", TC_ACT_SHOT},
+ {"shot", TC_ACT_SHOT},
+ {"pass", TC_ACT_OK},
+ {"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;
+ }
+ if (!allow_num || sscanf(arg, "%d%c", &n, &dummy) != 1)
+ return -1;
+
+ *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;
- if (matches(arg, "continue") == 0)
- res = -1;
- else if (matches(arg, "drop") == 0)
- res = TC_ACT_SHOT;
- else if (matches(arg, "shot") == 0)
- res = TC_ACT_SHOT;
- else if (matches(arg, "pass") == 0)
- res = TC_ACT_OK;
- else if (strcmp(arg, "ok") == 0)
- res = TC_ACT_OK;
- else if (matches(arg, "reclassify") == 0)
- res = TC_ACT_RECLASSIFY;
- else {
- char dummy;
- if (sscanf(arg, "%d%c", &res, &dummy) != 1)
+ 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, 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)
+{
+ char **argv = *argv_p;
+ int result1, result2;
+ 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)) {
+ if (p)
+ *p = '/';
+ return -1;
}
- *result = res;
+
+ *p = '/';
+ if (action_a2n(p + 1, &result2, allow_num))
+ return -1;
+
+ *result1_p = result1;
+ *result2_p = result2;
return 0;
}
-int get_linklayer(unsigned *val, const char *arg)
+void print_action_control(FILE *f, const char *prefix,
+ int action, const char *suffix)
+{
+ fprintf(f, "%s%s", prefix, action_n2a(action));
+ if (TC_ACT_EXT_CMP(action, TC_ACT_GOTO_CHAIN))
+ fprintf(f, " chain %u", action & TC_ACT_EXT_VAL_MASK);
+ if (TC_ACT_EXT_CMP(action, TC_ACT_JUMP))
+ fprintf(f, " %u", action & TC_ACT_EXT_VAL_MASK);
+ fprintf(f, "%s", suffix);
+}
+
+int get_linklayer(unsigned int *val, const char *arg)
{
int res;
@@ -477,7 +673,7 @@ int get_linklayer(unsigned *val, const char *arg)
return 0;
}
-void print_linklayer(char *buf, int len, unsigned linklayer)
+void print_linklayer(char *buf, int len, unsigned int linklayer)
{
switch (linklayer) {
case LINKLAYER_UNSPEC:
@@ -495,21 +691,22 @@ void print_linklayer(char *buf, int len, unsigned linklayer)
}
}
-char *sprint_linklayer(unsigned linklayer, char *buf)
+char *sprint_linklayer(unsigned int linklayer, char *buf)
{
print_linklayer(buf, SPRINT_BSIZE-1, linklayer);
return buf;
}
-void print_tm(FILE * f, const struct tcf_t *tm)
+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)(tm->install/hz));
+ fprintf(f, " installed %u sec", (unsigned int)(tm->install/hz));
if (tm->lastuse != 0)
- fprintf(f, " used %u sec", (unsigned)(tm->lastuse/hz));
+ fprintf(f, " used %u sec", (unsigned int)(tm->lastuse/hz));
if (tm->expires != 0)
- fprintf(f, " expires %u sec", (unsigned)(tm->expires/hz));
+ fprintf(f, " expires %u sec", (unsigned int)(tm->expires/hz));
}
void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats)
@@ -521,6 +718,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat
if (tbs[TCA_STATS_BASIC]) {
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);
@@ -528,6 +726,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat
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);
@@ -552,6 +751,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat
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)));
if (!tbs[TCA_STATS_RATE_EST])
fprintf(fp, "\n%s", prefix);
@@ -575,10 +775,9 @@ void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtat
}
/* backward compatibility */
if (tb[TCA_STATS]) {
- struct tc_stats st;
+ struct tc_stats st = {};
/* handle case where kernel returns more/less than we know about */
- memset(&st, 0, sizeof(st));
memcpy(&st, RTA_DATA(tb[TCA_STATS]), MIN(RTA_PAYLOAD(tb[TCA_STATS]), sizeof(st)));
fprintf(fp, "%sSent %llu bytes %u pkts (dropped %u, overlimits %u) ",