/* * q_etf.c Earliest TxTime First (ETF). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Vinicius Costa Gomes * Jesus Sanchez-Palencia * */ #include #include #include #include #include #include #include #include #include #include "utils.h" #include "tc_util.h" #define CLOCKID_INVALID (-1) static const struct static_clockid { const char *name; clockid_t clockid; } clockids_sysv[] = { { "REALTIME", CLOCK_REALTIME }, { "TAI", CLOCK_TAI }, { "BOOTTIME", CLOCK_BOOTTIME }, { "MONOTONIC", CLOCK_MONOTONIC }, { NULL } }; static void explain(void) { fprintf(stderr, "Usage: ... etf delta NANOS clockid CLOCKID [offload] [deadline_mode]\n" "CLOCKID must be a valid SYS-V id (i.e. CLOCK_TAI)\n"); } static void explain1(const char *arg, const char *val) { fprintf(stderr, "etf: illegal value for \"%s\": \"%s\"\n", arg, val); } static void explain_clockid(const char *val) { fprintf(stderr, "etf: illegal value for \"clockid\": \"%s\".\n" "It must be a valid SYS-V id (i.e. CLOCK_TAI)\n", val); } static int get_clockid(__s32 *val, const char *arg) { const struct static_clockid *c; /* Drop the CLOCK_ prefix if that is being used. */ if (strcasestr(arg, "CLOCK_") != NULL) arg += sizeof("CLOCK_") - 1; for (c = clockids_sysv; c->name; c++) { if (strcasecmp(c->name, arg) == 0) { *val = c->clockid; return 0; } } return -1; } static const char* get_clock_name(clockid_t clockid) { const struct static_clockid *c; for (c = clockids_sysv; c->name; c++) { if (clockid == c->clockid) return c->name; } return "invalid"; } static int etf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) { struct tc_etf_qopt opt = { .clockid = CLOCKID_INVALID, }; struct rtattr *tail; while (argc > 0) { if (matches(*argv, "offload") == 0) { if (opt.flags & TC_ETF_OFFLOAD_ON) { fprintf(stderr, "etf: duplicate \"offload\" specification\n"); return -1; } opt.flags |= TC_ETF_OFFLOAD_ON; } else if (matches(*argv, "deadline_mode") == 0) { if (opt.flags & TC_ETF_DEADLINE_MODE_ON) { fprintf(stderr, "etf: duplicate \"deadline_mode\" specification\n"); return -1; } opt.flags |= TC_ETF_DEADLINE_MODE_ON; } else if (matches(*argv, "delta") == 0) { NEXT_ARG(); if (opt.delta) { fprintf(stderr, "etf: duplicate \"delta\" specification\n"); return -1; } if (get_s32(&opt.delta, *argv, 0)) { explain1("delta", *argv); return -1; } } else if (matches(*argv, "clockid") == 0) { NEXT_ARG(); if (opt.clockid != CLOCKID_INVALID) { fprintf(stderr, "etf: duplicate \"clockid\" specification\n"); return -1; } if (get_clockid(&opt.clockid, *argv)) { explain_clockid(*argv); return -1; } } else if (strcmp(*argv, "skip_sock_check") == 0) { if (opt.flags & TC_ETF_SKIP_SOCK_CHECK) { fprintf(stderr, "etf: duplicate \"skip_sock_check\" specification\n"); return -1; } opt.flags |= TC_ETF_SKIP_SOCK_CHECK; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "etf: unknown parameter \"%s\"\n", *argv); explain(); return -1; } argc--; argv++; } tail = NLMSG_TAIL(n); addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); addattr_l(n, 2024, TCA_ETF_PARMS, &opt, sizeof(opt)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } static int etf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_ETF_MAX+1]; struct tc_etf_qopt *qopt; if (opt == NULL) return 0; parse_rtattr_nested(tb, TCA_ETF_MAX, opt); if (tb[TCA_ETF_PARMS] == NULL) return -1; qopt = RTA_DATA(tb[TCA_ETF_PARMS]); if (RTA_PAYLOAD(tb[TCA_ETF_PARMS]) < sizeof(*qopt)) return -1; print_string(PRINT_ANY, "clockid", "clockid %s ", get_clock_name(qopt->clockid)); print_uint(PRINT_ANY, "delta", "delta %d ", qopt->delta); print_string(PRINT_ANY, "offload", "offload %s ", (qopt->flags & TC_ETF_OFFLOAD_ON) ? "on" : "off"); print_string(PRINT_ANY, "deadline_mode", "deadline_mode %s ", (qopt->flags & TC_ETF_DEADLINE_MODE_ON) ? "on" : "off"); print_string(PRINT_ANY, "skip_sock_check", "skip_sock_check %s", (qopt->flags & TC_ETF_SKIP_SOCK_CHECK) ? "on" : "off"); return 0; } struct qdisc_util etf_qdisc_util = { .id = "etf", .parse_qopt = etf_parse_opt, .print_qopt = etf_print_opt, };