diff --git a/tc/Makefile b/tc/Makefile index 9d618ffc..7640c58e 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -1,6 +1,6 @@ TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o \ - m_police.o m_estimator.o m_action.o m_ematch.o \ - emp_ematch.yacc.o emp_ematch.lex.o + tc_monitor.o m_police.o m_estimator.o m_action.o \ + m_ematch.o emp_ematch.yacc.o emp_ematch.lex.o include ../Config diff --git a/tc/m_action.c b/tc/m_action.c index b4eff91c..c67bc883 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -313,7 +313,7 @@ tc_print_action(FILE * f, const struct rtattr *arg) return 0; } -static int do_print_action(const struct sockaddr_nl *who, +int print_action(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { @@ -333,7 +333,7 @@ static int do_print_action(const struct sockaddr_nl *who, if (NULL == tb[TCA_ACT_TAB]) { if (n->nlmsg_type != RTM_GETACTION) - fprintf(stderr, "do_print_action: NULL kind\n"); + fprintf(stderr, "print_action: NULL kind\n"); return -1; } @@ -454,7 +454,7 @@ int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) return 1; } - if (ans && do_print_action(NULL, &req.n, (void*)stdout) < 0) { + if (ans && print_action(NULL, &req.n, (void*)stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } @@ -556,7 +556,7 @@ int tc_act_list_or_flush(int argc, char **argv, int event) perror("Cannot send dump request"); return 1; } - ret = rtnl_dump_filter(&rth, do_print_action, stdout, NULL, NULL); + ret = rtnl_dump_filter(&rth, print_action, stdout, NULL, NULL); } if (event == RTM_DELACTION) { diff --git a/tc/tc.c b/tc/tc.c index fa36ee07..789f6f62 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -181,7 +181,7 @@ static void usage(void) { fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n" " tc [-force] -batch file\n" - "where OBJECT := { qdisc | class | filter | action }\n" + "where OBJECT := { qdisc | class | filter | action | monitor }\n" " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] [file] }\n"); } @@ -199,6 +199,9 @@ static int do_cmd(int argc, char **argv) if (matches(*argv, "actions") == 0) return do_action(argc-1, argv+1); + if (matches(*argv, "monitor") == 0) + return do_tcmonitor(argc-1, argv+1); + if (matches(*argv, "help") == 0) { usage(); return 0; diff --git a/tc/tc_class.c b/tc/tc_class.c index 93d5def5..8d93b5a8 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -147,7 +147,7 @@ int tc_class_modify(int cmd, unsigned flags, int argc, char **argv) int filter_ifindex; __u32 filter_qdisc; -static int print_class(const struct sockaddr_nl *who, +int print_class(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; diff --git a/tc/tc_common.h b/tc/tc_common.h index 7e135824..5bfc43e4 100644 --- a/tc/tc_common.h +++ b/tc/tc_common.h @@ -6,6 +6,11 @@ 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 do_tcmonitor(int argc, char **argv); +extern int print_action(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +extern int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +extern int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); + extern int print_class(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); struct tc_estimator; 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 58af0772..f3319d55 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -176,7 +176,7 @@ static int filter_ifindex; static __u32 filter_prio; static __u32 filter_protocol; -static int print_filter(const struct sockaddr_nl *who, +int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c new file mode 100644 index 00000000..1af6cf0a --- /dev/null +++ b/tc/tc_monitor.c @@ -0,0 +1,110 @@ +/* + * tc_monitor.c "tc monitor". + * + * 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: Jamal Hadi Salim + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt_names.h" +#include "utils.h" +#include "tc_util.h" +#include "tc_common.h" + + +static void usage(void) __attribute__((noreturn)); + +static void usage(void) +{ + fprintf(stderr, "Usage: tc monitor\n"); + exit(-1); +} + + +int accept_tcmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +{ + FILE *fp = (FILE*)arg; + + if (n->nlmsg_type == RTM_NEWTFILTER || n->nlmsg_type == RTM_DELTFILTER) { + print_filter(who, n, arg); + return 0; + } + if (n->nlmsg_type == RTM_NEWTCLASS || n->nlmsg_type == RTM_DELTCLASS) { + print_class(who, n, arg); + return 0; + } + if (n->nlmsg_type == RTM_NEWQDISC || n->nlmsg_type == RTM_DELQDISC) { + print_qdisc(who, n, arg); + return 0; + } + if (n->nlmsg_type == RTM_GETACTION || n->nlmsg_type == RTM_NEWACTION || + n->nlmsg_type == RTM_DELACTION) { + print_action(who, n, arg); + return 0; + } + if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP && + n->nlmsg_type != NLMSG_DONE) { + fprintf(fp, "Unknown message: length %08d type %08x flags %08x\n", + n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); + } + return 0; +} + +int do_tcmonitor(int argc, char **argv) +{ + struct rtnl_handle rth; + char *file = NULL; + unsigned groups = RTMGRP_TC; + + while (argc > 0) { + if (matches(*argv, "file") == 0) { + NEXT_ARG(); + file = *argv; + } else { + if (matches(*argv, "help") == 0) { + usage(); + } else { + fprintf(stderr, "Argument \"%s\" is unknown, try \"tc monitor help\".\n", *argv); + exit(-1); + } + } + argc--; argv++; + } + + if (file) { + FILE *fp; + fp = fopen(file, "r"); + if (fp == NULL) { + perror("Cannot fopen"); + exit(-1); + } + return rtnl_from_file(fp, accept_tcmsg, (void*)stdout); + } + + if (rtnl_open(&rth, groups) < 0) + exit(1); + + ll_init_map(&rth); + + if (rtnl_listen(&rth, accept_tcmsg, (void*)stdout) < 0) { + rtnl_close(&rth); + exit(2); + } + + rtnl_close(&rth); + exit(0); +} diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index fb107f46..50b26497 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -162,7 +162,7 @@ int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) static int filter_ifindex; -static int print_qdisc(const struct sockaddr_nl *who, +int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) {