diff --git a/tc/f_u32.c b/tc/f_u32.c index 3e76e9cf..923a68b3 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "utils.h" #include "tc_util.h" @@ -122,6 +123,8 @@ static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int return -1; sel->keys[i].val |= key; sel->keys[i].mask |= mask; + sel->keys[i].off = 0; + sel->keys[i].offmask = 0; return 0; } } @@ -367,7 +370,8 @@ static int parse_ip6_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, i plen = addr.bitlen; for (i=0; i 0) { if (matches(*argv, "mask") == 0) { __u32 mask; + int i = 0; NEXT_ARG(); if (get_u32(&mask, *argv, 16)) return -1; sel->hmask = htonl(mask); + mask = sel->hmask; + while (!(mask & 1)) { + i++; + mask>>=1; + } +#ifdef fix_u32_bug + sel->fshift = i; +#endif } else if (matches(*argv, "at") == 0) { int num; NEXT_ARG(); @@ -753,7 +766,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char ** return 0; tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len)); - addattr_l(n, 4096, TCA_OPTIONS, NULL, 0); + addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); while (argc > 0) { if (matches(*argv, "match") == 0) { @@ -786,7 +799,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char ** fprintf(stderr, "Illegal \"classid\"\n"); return -1; } - addattr_l(n, 4096, TCA_U32_CLASSID, &handle, 4); + addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4); sel.sel.flags |= TC_U32_TERMINAL; } else if (matches(*argv, "divisor") == 0) { unsigned divisor; @@ -796,7 +809,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char ** fprintf(stderr, "Illegal \"divisor\"\n"); return -1; } - addattr_l(n, 4096, TCA_U32_DIVISOR, &divisor, 4); + addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4); } else if (matches(*argv, "order") == 0) { NEXT_ARG(); if (get_u32(&order, *argv, 0)) { @@ -814,7 +827,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char ** fprintf(stderr, "\"link\" must be a hash table.\n"); return -1; } - addattr_l(n, 4096, TCA_U32_LINK, &handle, 4); + addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4); } else if (strcmp(*argv, "ht") == 0) { unsigned handle; NEXT_ARG(); @@ -851,6 +864,24 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char ** htid = ((hash<<12)&0xFF000)|(htid&0xFFF00000); sample_ok = 1; continue; + } else if (strcmp(*argv, "indev") == 0) { + char ind[IFNAMSIZ + 1]; + memset(ind, 0, sizeof (ind)); + argc--; + argv++; + if (argc < 1) { + fprintf(stderr, "Illegal indev\n"); + return -1; + } + strncpy(ind, *argv, sizeof (ind) - 1); + addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1); + } else if (matches(*argv, "action") == 0) { + NEXT_ARG(); + if (parse_action(&argc, &argv, TCA_U32_ACT, n)) { + fprintf(stderr, "Illegal \"action\"\n"); + return -1; + } + continue; } else if (matches(*argv, "police") == 0) { NEXT_ARG(); if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) { @@ -878,9 +909,9 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char ** } if (htid) - addattr_l(n, 4096, TCA_U32_HASH, &htid, 4); + addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4); if (sel_ok) - addattr_l(n, 4096, TCA_U32_SEL, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key)); + addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key)); tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail; return 0; } @@ -932,22 +963,19 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __ SPRINT_BUF(b1); fprintf(f, "link %s ", sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1)); } - if (tb[TCA_U32_POLICE]) { - fprintf(f, "\n"); - tc_print_police(f, tb[TCA_U32_POLICE]); - } + if (sel) { int i; struct tc_u32_key *key = sel->keys; - if (sel->nkeys) { - for (i=0; inkeys; i++, key++) + for (i=0; inkeys; i++, key++) { fprintf(f, "\n match %08x/%08x at %s%d", (unsigned int)ntohl(key->val), (unsigned int)ntohl(key->mask), key->offmask ? "nexthdr+" : "", key->off); + } } if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) { @@ -966,6 +994,23 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __ } } + if (show_stats && tb[TCA_U32_PCNT]){ + struct tc_u32_pcnt *p = RTA_DATA(tb[TCA_U32_PCNT]); + fprintf(f, " (rule hit %llu success %llu)", + p->rcnt, p->rhit); + } + if (tb[TCA_U32_POLICE]) { + fprintf(f, "\n"); + tc_print_police(f, tb[TCA_U32_POLICE]); + } + if (tb[TCA_U32_INDEV]) { + struct rtattr *idev = tb[TCA_U32_INDEV]; + fprintf(f, "\n input dev %s\n", (char *) RTA_DATA(idev)); + } + if (tb[TCA_U32_ACT]) { + tc_print_action(f, tb[TCA_U32_ACT]); + } + return 0; } diff --git a/tc/m_police.c b/tc/m_police.c index 0e76efc5..79025a5d 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -9,6 +9,8 @@ * Authors: Alexey Kuznetsov, * FIXES: 19990619 - J Hadi Salim (hadi@cyberus.ca) * simple addattr packaging fix. + * 2002: J Hadi Salim - Add tc action extensions syntax + * */ #include @@ -24,12 +26,22 @@ #include "utils.h" #include "tc_util.h" +struct action_util police_util = { + .id = "police", + .parse_aopt = act_parse_police, + .print_aopt = print_police, + .print_xstats = police_print_xstats, +}; + static void explain(void) { fprintf(stderr, "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n"); fprintf(stderr, " [ peakrate BPS ] [ avrate BPS ]\n"); - fprintf(stderr, " [ ACTION ]\n"); - fprintf(stderr, "Where: ACTION := reclassify | drop | continue \n"); + fprintf(stderr, " [ ACTIONTERM ]\n"); + fprintf(stderr, "Old Syntax ACTIOTERMN := action [/NOTEXCEEDACT] \n"); + fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed [/NOTEXCEEDACT] \n"); + fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue \n"); + fprintf(stderr, "Where: pipe is only valid for new syntax \n"); } static void explain1(char *arg) @@ -54,6 +66,8 @@ char *police_action_n2a(int action, char *buf, int len) break; case TC_POLICE_RECLASSIFY: return "reclassify"; + case TC_POLICE_PIPE: + return "pipe"; default: snprintf(buf, len, "%d", action); return buf; @@ -76,6 +90,8 @@ int police_action_a2n(char *arg, int *result) res = TC_POLICE_OK; else if (matches(arg, "reclassify") == 0) res = TC_POLICE_RECLASSIFY; + else if (matches(arg, "pipe") == 0) + res = TC_POLICE_PIPE; else { char dummy; if (sscanf(arg, "%d%c", &res, &dummy) != 1) @@ -107,7 +123,8 @@ int get_police_result(int *action, int *result, char *arg) return 0; } -int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) + +int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; @@ -125,13 +142,17 @@ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) memset(&p, 0, sizeof(p)); p.action = TC_POLICE_RECLASSIFY; + if (a) /* new way of doing things */ + NEXT_ARG(); + if (argc <= 0) return -1; while (argc > 0) { + if (matches(*argv, "index") == 0) { NEXT_ARG(); - if (get_u32(&p.index, *argv, 16)) { + if (get_u32(&p.index, *argv, 10)) { fprintf(stderr, "Illegal \"index\"\n"); return -1; } @@ -207,7 +228,9 @@ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) p.action = TC_POLICE_UNSPEC; } else if (matches(*argv, "pass") == 0) { p.action = TC_POLICE_OK; - } else if (strcmp(*argv, "action") == 0) { + } else if (matches(*argv, "pipe") == 0) { + p.action = TC_POLICE_PIPE; + } else if (strcmp(*argv, "conform-exceed") == 0) { NEXT_ARG(); if (get_police_result(&p.action, &presult, *argv)) { fprintf(stderr, "Illegal \"action\"\n"); @@ -261,18 +284,16 @@ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) } tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len)); - addattr_l(n, 1024, tca_id, NULL, 0); - addattr_l(n, 2024, TCA_POLICE_TBF, &p, sizeof(p)); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_POLICE_TBF, &p, sizeof(p)); if (p.rate.rate) - addattr_l(n, 3024, TCA_POLICE_RATE, rtab, 1024); + addattr_l(n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024); if (p.peakrate.rate) - addattr_l(n, 4096, TCA_POLICE_PEAKRATE, ptab, 1024); + addattr_l(n, MAX_MSG, TCA_POLICE_PEAKRATE, ptab, 1024); if (avrate) - addattr32(n, 4096, TCA_POLICE_AVRATE, avrate); + addattr32(n, MAX_MSG, TCA_POLICE_AVRATE, avrate); if (presult) - addattr32(n, 4096, TCA_POLICE_RESULT, presult); -#if 0 -#endif + addattr32(n, MAX_MSG, TCA_POLICE_RESULT, presult); tail->rta_len = (((void*)n)+NLMSG_ALIGN(n->nlmsg_len)) - (void*)tail; res = 0; @@ -282,8 +303,13 @@ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) return res; } +int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) +{ + return act_parse_police(NULL,argc_p,argv_p,tca_id,n); +} -int tc_print_police(FILE *f, struct rtattr *arg) +int +print_police(struct action_util *a,FILE *f, struct rtattr *arg) { SPRINT_BUF(b1); struct tc_police *p; @@ -300,18 +326,15 @@ int tc_print_police(FILE *f, struct rtattr *arg) fprintf(f, "[NULL police tbf]"); return 0; } +#ifndef STOOPID_8BYTE if (RTA_PAYLOAD(tb[TCA_POLICE_TBF]) < sizeof(*p)) { fprintf(f, "[truncated police tbf]"); return -1; } +#endif p = RTA_DATA(tb[TCA_POLICE_TBF]); - fprintf(f, "police %x ", p->index); - fprintf(f, "action %s", police_action_n2a(p->action, b1, sizeof(b1))); - if (tb[TCA_POLICE_RESULT]) { - fprintf(f, "/%s ", police_action_n2a(*(int*)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); - } else - fprintf(f, " "); + fprintf(f, " police 0x%x ", p->index); fprintf(f, "rate %s ", sprint_rate(p->rate.rate, b1)); buffer = ((double)p->rate.rate*tc_core_tick2usec(p->burst))/1000000; fprintf(f, "burst %s ", sprint_size(buffer, b1)); @@ -322,7 +345,24 @@ int tc_print_police(FILE *f, struct rtattr *arg) fprintf(f, "peakrate %s ", sprint_rate(p->peakrate.rate, b1)); if (tb[TCA_POLICE_AVRATE]) fprintf(f, "avrate %s ", sprint_rate(*(__u32*)RTA_DATA(tb[TCA_POLICE_AVRATE]), b1)); + fprintf(f, "action %s", police_action_n2a(p->action, b1, sizeof(b1))); + if (tb[TCA_POLICE_RESULT]) { + fprintf(f, "/%s ", police_action_n2a(*(int*)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); + } else + fprintf(f, " "); + fprintf(f, "\nref %d bind %d\n",p->refcnt, p->bindcnt); return 0; } +int +tc_print_police(FILE *f, struct rtattr *arg) { + return print_police(&police_util,f,arg); +} + +int +police_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats) +{ + return 0; +} + diff --git a/tc/tc.c b/tc/tc.c index b3487512..abf56f5b 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -176,7 +176,7 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { qdisc | class | filter }\n" + "where OBJECT := { qdisc | class | filter | action }\n" " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] file }\n"); exit(-1); } @@ -242,6 +242,8 @@ int main(int argc, char **argv) ret += do_class(largc-1, largv+1); } else if (matches(largv[0], "filter") == 0) { ret += do_filter(largc-1, largv+1); + } else if (matches(largv[0], "action") == 0) { + ret += do_action(largc-1, largv+1); } else if (matches(largv[0], "help") == 0) { usage(); /* note that usage() doesn't return */ } else { @@ -286,6 +288,8 @@ int main(int argc, char **argv) return do_class(argc-2, argv+2); if (matches(argv[1], "filter") == 0) return do_filter(argc-2, argv+2); + if (matches(argv[1], "actions") == 0) + return do_action(argc-2, argv+2); if (matches(argv[1], "help") == 0) usage(); fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n", argv[1]); diff --git a/tc/tc_class.c b/tc/tc_class.c index 542f8d5f..0c91f42f 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -201,7 +201,7 @@ int print_class(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { - fprintf(stderr, "NULL kind\n"); + fprintf(stderr, "print_class: NULL kind\n"); return -1; } @@ -241,14 +241,18 @@ int print_class(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "\n"); if (show_stats) { if (tb[TCA_STATS]) { +#ifndef STOOPID_8BYTE if (RTA_PAYLOAD(tb[TCA_STATS]) < sizeof(struct tc_stats)) fprintf(fp, "statistics truncated"); else { +#endif struct tc_stats st; memcpy(&st, RTA_DATA(tb[TCA_STATS]), sizeof(st)); print_class_tcstats(fp, &st); fprintf(fp, "\n"); +#ifndef STOOPID_8BYTE } +#endif } if (q && tb[TCA_XSTATS]) { q->print_xstats(q, fp, tb[TCA_XSTATS]); @@ -323,11 +327,13 @@ int tc_class_list(int argc, char **argv) if (rtnl_dump_request(&rth, RTM_GETTCLASS, &t, sizeof(t)) < 0) { perror("Cannot send dump request"); + rtnl_close(&rth); exit(1); } if (rtnl_dump_filter(&rth, print_class, stdout, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); + rtnl_close(&rth); exit(1); } diff --git a/tc/tc_common.h b/tc/tc_common.h index d695ca2d..e19a867e 100644 --- a/tc/tc_common.h +++ b/tc/tc_common.h @@ -1,5 +1,6 @@ extern int do_qdisc(int argc, char **argv); extern int do_class(int argc, char **argv); extern int do_filter(int argc, char **argv); +extern int do_action(int argc, char **argv); extern int parse_estimator(int *p_argc, char ***p_argv, struct tc_estimator *est); diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 300c3e70..2cace200 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -53,7 +53,7 @@ int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) struct { struct nlmsghdr n; struct tcmsg t; - char buf[4096]; + char buf[MAX_MSG]; } req; struct filter_util *q = NULL; __u32 prio = 0; @@ -165,12 +165,16 @@ int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) if ((req.t.tcm_ifindex = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); + rtnl_close(&rth); exit(1); } } - if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { + fprintf(stderr, "We have an error talking to the kernel\n"); + rtnl_close(&rth); exit(2); + } rtnl_close(&rth); return 0; @@ -204,7 +208,7 @@ int print_filter(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { - fprintf(stderr, "NULL kind\n"); + fprintf(stderr, "print_filter: NULL kind\n"); return -1; } @@ -250,14 +254,18 @@ int print_filter(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (show_stats) { if (tb[TCA_STATS]) { +#ifndef STOOPID_8BYTE if (RTA_PAYLOAD(tb[TCA_STATS]) < sizeof(struct tc_stats)) fprintf(fp, "statistics truncated"); else { +#endif struct tc_stats st; memcpy(&st, RTA_DATA(tb[TCA_STATS]), sizeof(st)); print_tcstats(fp, &st); fprintf(fp, "\n"); +#ifndef STOOPID_8BYTE } +#endif } } fflush(fp); @@ -342,6 +350,7 @@ int tc_filter_list(int argc, char **argv) if (d[0]) { if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); + rtnl_close(&rth); exit(1); } filter_ifindex = t.tcm_ifindex; @@ -349,6 +358,7 @@ int tc_filter_list(int argc, char **argv) if (rtnl_dump_request(&rth, RTM_GETTFILTER, &t, sizeof(t)) < 0) { perror("Cannot send dump request"); + rtnl_close(&rth); exit(1); } diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 361ca8aa..c7f22e17 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -141,6 +141,7 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) if (rtnl_open(&rth, 0) < 0) { fprintf(stderr, "Cannot open rtnetlink\n"); + rtnl_close(&rth); exit(1); } @@ -151,13 +152,16 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) if ((idx = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); + rtnl_close(&rth); exit(1); } req.t.tcm_ifindex = idx; } - if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { + rtnl_close(&rth); exit(2); + } rtnl_close(&rth); return 0; @@ -167,8 +171,9 @@ void print_tcstats(FILE *fp, struct tc_stats *st) { SPRINT_BUF(b1); - fprintf(fp, " Sent %llu bytes %u pkts (dropped %u, overlimits %u) ", + fprintf(fp, " Sent %llu bytes %u pkts (dropped %u, overlimits %u ) ", (unsigned long long)st->bytes, st->packets, st->drops, st->overlimits); + if (st->bps || st->pps || st->qlen || st->backlog) { fprintf(fp, "\n "); if (st->bps || st->pps) { @@ -216,7 +221,7 @@ int print_qdisc(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { - fprintf(stderr, "NULL kind\n"); + fprintf(stderr, "print_qdisc: NULL kind\n"); return -1; } @@ -235,7 +240,13 @@ int print_qdisc(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (t->tcm_info != 1) { fprintf(fp, "refcnt %d ", t->tcm_info); } - q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND])); + /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ + + if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND]))) + q = get_qdisc_kind("prio"); + else + q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND])); + if (tb[TCA_OPTIONS]) { if (q) q->print_qopt(q, fp, tb[TCA_OPTIONS]); @@ -245,15 +256,19 @@ int print_qdisc(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "\n"); if (show_stats) { if (tb[TCA_STATS]) { +#ifndef STOOPID_8BYTE if (RTA_PAYLOAD(tb[TCA_STATS]) < sizeof(struct tc_stats)) fprintf(fp, "statistics truncated"); else { +#endif struct tc_stats st; memcpy(&st, RTA_DATA(tb[TCA_STATS]), sizeof(st)); print_tcstats(fp, &st); fprintf(fp, "\n"); } +#ifndef STOOPID_8BYTE } +#endif if (q && tb[TCA_XSTATS]) { q->print_xstats(q, fp, tb[TCA_XSTATS]); fprintf(fp, "\n"); @@ -306,6 +321,7 @@ int tc_qdisc_list(int argc, char **argv) if (d[0]) { if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); + rtnl_close(&rth); exit(1); } filter_ifindex = t.tcm_ifindex; @@ -313,11 +329,13 @@ int tc_qdisc_list(int argc, char **argv) if (rtnl_dump_request(&rth, RTM_GETQDISC, &t, sizeof(t)) < 0) { perror("Cannot send dump request"); + rtnl_close(&rth); exit(1); } if (rtnl_dump_filter(&rth, print_qdisc, stdout, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); + rtnl_close(&rth); exit(1); } diff --git a/tc/tc_util.c b/tc/tc_util.c index d87085c2..ad72b63e 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -369,4 +369,62 @@ char * sprint_qdisc_handle(__u32 h, char *buf) return buf; } +char * action_n2a(int action, char *buf, int len) +{ + switch (action) { + case -1: + 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"; + default: + snprintf(buf, len, "%d", action); + return buf; + } +} +int action_a2n(char *arg, int *result) +{ + int res; + + 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) + return -1; + } + *result = res; + return 0; +} + +void print_tm(FILE * f, struct tcf_t *tm) +{ + int hz = get_hz(); + if (tm->install != 0) + fprintf(f, " installed %d sec", tm->install/hz); + if (tm->lastuse != 0) + fprintf(f, " used %d sec", tm->lastuse/hz); + if (tm->expires != 0) + fprintf(f, " expires %d sec", tm->expires/hz); +} diff --git a/tc/tc_util.h b/tc/tc_util.h index b3d70da9..3a257608 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -1,13 +1,14 @@ #ifndef _TC_UTIL_H_ #define _TC_UTIL_H_ 1 +#define MAX_MSG 16384 #include #include #include "tc_core.h" struct qdisc_util { - struct qdisc_util *next; + struct qdisc_util *next; char id[16]; int (*parse_qopt)(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n); int (*print_qopt)(struct qdisc_util *qu, FILE *f, struct rtattr *opt); @@ -25,6 +26,16 @@ struct filter_util int (*print_fopt)(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle); }; +struct action_util +{ + struct action_util *next; + char id[16]; + int (*parse_aopt)(struct action_util *a, int *argc, char ***argv, int code, struct nlmsghdr *n); + int (*print_aopt)(struct action_util *au, FILE *f, struct rtattr *opt); + int (*print_xstats)(struct action_util *au, FILE *f, struct rtattr *xstats); + +}; + extern struct qdisc_util *get_qdisc_kind(const char *str); extern struct filter_util *get_filter_kind(const char *str); @@ -56,5 +67,14 @@ extern char * sprint_tc_classid(__u32 h, char *buf); extern int tc_print_police(FILE *f, struct rtattr *tb); extern int parse_police(int *, char ***, int, struct nlmsghdr *); +extern char *action_n2a(int action, char *buf, int len); +extern int action_a2n(char *arg, int *result); +extern int act_parse_police(struct action_util *a,int *, char ***, int, struct nlmsghdr *); +extern int print_police(struct action_util *a,FILE *f, struct rtattr *tb); +extern int police_print_xstats(struct action_util *a,FILE *f, struct rtattr *tb); +extern int tc_print_action(FILE *f, struct rtattr *tb); +extern int tc_print_ipt(FILE *f, struct rtattr *tb); +extern int parse_action(int *, char ***, int, struct nlmsghdr *); +extern void print_tm(FILE *f, struct tcf_t *tm); #endif