diff options
Diffstat (limited to 'tc')
-rw-r--r-- | tc/Android.mk | 2 | ||||
-rw-r--r-- | tc/Makefile | 70 | ||||
-rw-r--r-- | tc/e_bpf.c | 9 | ||||
-rw-r--r-- | tc/em_canid.c | 4 | ||||
-rw-r--r-- | tc/em_cmp.c | 6 | ||||
-rw-r--r-- | tc/em_ipset.c | 54 | ||||
-rw-r--r-- | tc/em_meta.c | 34 | ||||
-rw-r--r-- | tc/em_nbyte.c | 6 | ||||
-rw-r--r-- | tc/em_u32.c | 7 | ||||
-rw-r--r-- | tc/f_basic.c | 11 | ||||
-rw-r--r-- | tc/f_bpf.c | 102 | ||||
-rw-r--r-- | tc/f_cgroup.c | 6 | ||||
-rw-r--r-- | tc/f_flow.c | 10 | ||||
-rw-r--r-- | tc/f_flower.c | 1002 | ||||
-rw-r--r-- | tc/f_fw.c | 40 | ||||
-rw-r--r-- | tc/f_matchall.c | 157 | ||||
-rw-r--r-- | tc/f_route.c | 16 | ||||
-rw-r--r-- | tc/f_rsvp.c | 30 | ||||
-rw-r--r-- | tc/f_tcindex.c | 82 | ||||
-rw-r--r-- | tc/f_u32.c | 210 | ||||
-rw-r--r-- | tc/m_action.c | 301 | ||||
-rw-r--r-- | tc/m_bpf.c | 93 | ||||
-rw-r--r-- | tc/m_connmark.c | 34 | ||||
-rw-r--r-- | tc/m_csum.c | 59 | ||||
-rw-r--r-- | tc/m_ematch.c | 18 | ||||
-rw-r--r-- | tc/m_estimator.c | 2 | ||||
-rw-r--r-- | tc/m_gact.c | 102 | ||||
-rw-r--r-- | tc/m_ife.c | 336 | ||||
-rw-r--r-- | tc/m_ipt.c | 233 | ||||
-rw-r--r-- | tc/m_mirred.c | 101 | ||||
-rw-r--r-- | tc/m_nat.c | 50 | ||||
-rw-r--r-- | tc/m_pedit.c | 553 | ||||
-rw-r--r-- | tc/m_pedit.h | 62 | ||||
-rw-r--r-- | tc/m_police.c | 185 | ||||
-rw-r--r-- | tc/m_sample.c | 184 | ||||
-rw-r--r-- | tc/m_simple.c | 40 | ||||
-rw-r--r-- | tc/m_skbedit.c | 80 | ||||
-rw-r--r-- | tc/m_skbmod.c | 236 | ||||
-rw-r--r-- | tc/m_tunnel_key.c | 315 | ||||
-rw-r--r-- | tc/m_vlan.c | 96 | ||||
-rw-r--r-- | tc/m_xt.c | 254 | ||||
-rw-r--r-- | tc/m_xt_old.c | 129 | ||||
-rw-r--r-- | tc/p_eth.c | 75 | ||||
-rw-r--r-- | tc/p_icmp.c | 5 | ||||
-rw-r--r-- | tc/p_ip.c | 68 | ||||
-rw-r--r-- | tc/p_ip6.c | 91 | ||||
-rw-r--r-- | tc/p_tcp.c | 40 | ||||
-rw-r--r-- | tc/p_udp.c | 33 | ||||
-rw-r--r-- | tc/q_atm.c | 119 | ||||
-rw-r--r-- | tc/q_cbq.c | 88 | ||||
-rw-r--r-- | tc/q_choke.c | 10 | ||||
-rw-r--r-- | tc/q_clsact.c | 1 | ||||
-rw-r--r-- | tc/q_codel.c | 25 | ||||
-rw-r--r-- | tc/q_drr.c | 2 | ||||
-rw-r--r-- | tc/q_dsmark.c | 65 | ||||
-rw-r--r-- | tc/q_fifo.c | 5 | ||||
-rw-r--r-- | tc/q_fq.c | 24 | ||||
-rw-r--r-- | tc/q_fq_codel.c | 55 | ||||
-rw-r--r-- | tc/q_gred.c | 53 | ||||
-rw-r--r-- | tc/q_hfsc.c | 18 | ||||
-rw-r--r-- | tc/q_hhf.c | 29 | ||||
-rw-r--r-- | tc/q_htb.c | 61 | ||||
-rw-r--r-- | tc/q_ingress.c | 1 | ||||
-rw-r--r-- | tc/q_mqprio.c | 10 | ||||
-rw-r--r-- | tc/q_multiq.c | 4 | ||||
-rw-r--r-- | tc/q_netem.c | 52 | ||||
-rw-r--r-- | tc/q_pie.c | 11 | ||||
-rw-r--r-- | tc/q_prio.c | 11 | ||||
-rw-r--r-- | tc/q_qfq.c | 13 | ||||
-rw-r--r-- | tc/q_red.c | 11 | ||||
-rw-r--r-- | tc/q_rr.c | 9 | ||||
-rw-r--r-- | tc/q_sfb.c | 20 | ||||
-rw-r--r-- | tc/q_sfq.c | 5 | ||||
-rw-r--r-- | tc/q_tbf.c | 36 | ||||
-rw-r--r-- | tc/tc.c | 44 | ||||
-rw-r--r-- | tc/tc_bpf.c | 1892 | ||||
-rw-r--r-- | tc/tc_bpf.h | 79 | ||||
-rw-r--r-- | tc/tc_cbq.c | 9 | ||||
-rw-r--r-- | tc/tc_class.c | 54 | ||||
-rw-r--r-- | tc/tc_core.c | 38 | ||||
-rw-r--r-- | tc/tc_estimator.c | 9 | ||||
-rw-r--r-- | tc/tc_exec.c | 12 | ||||
-rw-r--r-- | tc/tc_filter.c | 394 | ||||
-rw-r--r-- | tc/tc_monitor.c | 6 | ||||
-rw-r--r-- | tc/tc_qdisc.c | 127 | ||||
-rw-r--r-- | tc/tc_red.c | 20 | ||||
-rw-r--r-- | tc/tc_stab.c | 12 | ||||
-rw-r--r-- | tc/tc_util.c | 307 | ||||
-rw-r--r-- | tc/tc_util.h | 157 |
89 files changed, 5307 insertions, 4224 deletions
diff --git a/tc/Android.mk b/tc/Android.mk index 467b08a0..78463a86 100644 --- a/tc/Android.mk +++ b/tc/Android.mk @@ -12,7 +12,7 @@ LOCAL_SYSTEM_SHARED_LIBRARIES := \ LOCAL_SHARED_LIBRARIES += libiprouteutil libnetlink -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include $(UAPI_INCLUDES) LOCAL_CFLAGS := -O2 -g -W -Wall -Wno-pointer-arith -Wno-sign-compare -Werror \ -Wno-unused-parameter \ diff --git a/tc/Makefile b/tc/Makefile index f5bea877..777de5e6 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -1,12 +1,8 @@ TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o tc_monitor.o \ - tc_exec.o tc_bpf.o m_police.o m_estimator.o m_action.o m_ematch.o \ + tc_exec.o m_police.o m_estimator.o m_action.o m_ematch.o \ emp_ematch.yacc.o emp_ematch.lex.o -include ../Config - -ifeq ($(IP_CONFIG_SETNS),y) - CFLAGS += -DHAVE_SETNS -endif +include ../config.mk SHARED_LIBS ?= y @@ -43,14 +39,20 @@ TCMODULES += m_gact.o TCMODULES += m_mirred.o TCMODULES += m_nat.o TCMODULES += m_pedit.o +TCMODULES += m_ife.o TCMODULES += m_skbedit.o +TCMODULES += m_skbmod.o TCMODULES += m_csum.o TCMODULES += m_simple.o TCMODULES += m_vlan.o TCMODULES += m_connmark.o TCMODULES += m_bpf.o +TCMODULES += m_tunnel_key.o +TCMODULES += m_sample.o TCMODULES += p_ip.o +TCMODULES += p_ip6.o TCMODULES += p_icmp.o +TCMODULES += p_eth.o TCMODULES += p_tcp.o TCMODULES += p_udp.o TCMODULES += em_nbyte.o @@ -66,40 +68,35 @@ TCMODULES += q_pie.o TCMODULES += q_hhf.o TCMODULES += q_clsact.o TCMODULES += e_bpf.o - -ifeq ($(TC_CONFIG_IPSET), y) - ifeq ($(TC_CONFIG_XT), y) - TCMODULES += em_ipset.o - endif -endif +TCMODULES += f_matchall.o TCSO := ifeq ($(TC_CONFIG_ATM),y) TCSO += q_atm.so endif -ifeq ($(TC_CONFIG_XT),y) - TCSO += m_xt.so -else - ifeq ($(TC_CONFIG_XT_OLD),y) - TCSO += m_xt_old.so +ifneq ($(TC_CONFIG_NO_XT),y) + ifeq ($(TC_CONFIG_XT),y) + TCSO += m_xt.so + ifeq ($(TC_CONFIG_IPSET),y) + TCMODULES += em_ipset.o + endif else - ifeq ($(TC_CONFIG_XT_OLD_H),y) - CFLAGS += -DTC_CONFIG_XT_H - TCSO += m_xt_old.so + ifeq ($(TC_CONFIG_XT_OLD),y) + TCSO += m_xt_old.so else - TCMODULES += m_ipt.o + ifeq ($(TC_CONFIG_XT_OLD_H),y) + CFLAGS += -DTC_CONFIG_XT_H + TCSO += m_xt_old.so + else + TCMODULES += m_ipt.o + endif endif endif endif -ifeq ($(TC_CONFIG_ELF),y) - CFLAGS += -DHAVE_ELF - LDLIBS += -lelf -endif - TCOBJ += $(TCMODULES) -LDLIBS += -L. -ltc -lm +LDLIBS += -L. -lm ifeq ($(SHARED_LIBS),y) LDLIBS += -ldl @@ -124,15 +121,16 @@ CFLAGS += -DYY_NO_INPUT MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc %.so: %.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic $< -o $@ + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic $< -o $@ -all: libtc.a tc $(TCSO) +all: tc $(TCSO) -tc: $(TCOBJ) $(TCLIB) +tc: $(TCOBJ) $(LIBNETLINK) libtc.a + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ libtc.a: $(TCLIB) - $(AR) rcs $@ $(TCLIB) + $(QUIET_AR)$(AR) rcs $@ $^ install: all mkdir -p $(MODDESTDIR) @@ -153,21 +151,21 @@ clean: rm -f emp_ematch.yacc.* q_atm.so: q_atm.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o q_atm.so q_atm.c -latm + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o q_atm.so q_atm.c -latm m_xt.so: m_xt.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o m_xt.so m_xt.c $$($(PKG_CONFIG) xtables --cflags --libs) + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o m_xt.so m_xt.c $$($(PKG_CONFIG) xtables --cflags --libs) m_xt_old.so: m_xt_old.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o m_xt_old.so m_xt_old.c $$($(PKG_CONFIG) xtables --cflags --libs) + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o m_xt_old.so m_xt_old.c $$($(PKG_CONFIG) xtables --cflags --libs) em_ipset.o: CFLAGS += $$($(PKG_CONFIG) xtables --cflags) %.yacc.c: %.y - $(YACC) $(YACCFLAGS) -o $@ $< + $(QUIET_YACC)$(YACC) $(YACCFLAGS) -o $@ $< %.lex.c: %.l - $(LEX) $(LEXFLAGS) -o$@ $< + $(QUIET_LEX)$(LEX) $(LEXFLAGS) -o$@ $< # our lexer includes the header from yacc, so make sure # we don't attempt to compile it before the header has @@ -15,8 +15,8 @@ #include "utils.h" #include "tc_util.h" -#include "tc_bpf.h" +#include "bpf_util.h" #include "bpf_elf.h" #include "bpf_scm.h" @@ -56,8 +56,8 @@ static int parse_bpf(struct exec_util *eu, int argc, char **argv) char **argv_run = argv_default, **envp_run, *tmp; int ret, i, env_old, env_num, env_map; const char *bpf_uds_name = NULL; - int fds[BPF_SCM_MAX_FDS]; - struct bpf_map_aux aux; + int fds[BPF_SCM_MAX_FDS] = {}; + struct bpf_map_aux aux = {}; if (argc == 0) return 0; @@ -115,9 +115,6 @@ static int parse_bpf(struct exec_util *eu, int argc, char **argv) return -1; } - memset(fds, 0, sizeof(fds)); - memset(&aux, 0, sizeof(aux)); - ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds)); if (ret < 0) { fprintf(stderr, "bpf: Could not receive fds!\n"); diff --git a/tc/em_canid.c b/tc/em_canid.c index 16f6ed5c..ceb64cb9 100644 --- a/tc/em_canid.c +++ b/tc/em_canid.c @@ -106,8 +106,8 @@ static int canid_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, if (args == NULL) return PARSE_ERR(args, "canid: missing arguments"); - rules.rules_raw = malloc(sizeof(struct can_filter) * rules.rules_capacity); - memset(rules.rules_raw, 0, sizeof(struct can_filter) * rules.rules_capacity); + rules.rules_raw = calloc(rules.rules_capacity, + sizeof(struct can_filter)); do { if (!bstrcmp(args, "sff")) { diff --git a/tc/em_cmp.c b/tc/em_cmp.c index 3e6d00e5..8ea0accf 100644 --- a/tc/em_cmp.c +++ b/tc/em_cmp.c @@ -44,12 +44,10 @@ static int cmp_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, int align, opnd = 0; unsigned long offset = 0, layer = TCF_LAYER_NETWORK, mask = 0, value = 0; int offset_present = 0, value_present = 0; - struct tcf_em_cmp cmp; - - memset(&cmp, 0, sizeof(cmp)); + struct tcf_em_cmp cmp = {}; #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &cmp_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &cmp_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "cmp: missing arguments"); diff --git a/tc/em_ipset.c b/tc/em_ipset.c index a2d0d15a..48b287f5 100644 --- a/tc/em_ipset.c +++ b/tc/em_ipset.c @@ -52,8 +52,8 @@ union ip_set_name_index { #define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */ struct ip_set_req_get_set { - unsigned op; - unsigned version; + unsigned int op; + unsigned int version; union ip_set_name_index set; }; @@ -62,14 +62,14 @@ struct ip_set_req_get_set { #define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ struct ip_set_req_version { - unsigned op; - unsigned version; + unsigned int op; + unsigned int version; }; #endif /* IPSET_INVALID_ID */ extern struct ematch_util ipset_ematch_util; -static int get_version(unsigned *version) +static int get_version(unsigned int *version) { int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); struct ip_set_req_version req_version; @@ -84,6 +84,7 @@ static int get_version(unsigned *version) res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size); if (res != 0) { perror("xt_set getsockopt"); + close(sockfd); return -1; } @@ -95,6 +96,7 @@ static int do_getsockopt(struct ip_set_req_get_set *req) { int sockfd, res; socklen_t size = sizeof(struct ip_set_req_get_set); + sockfd = get_version(&req->version); if (sockfd < 0) return -1; @@ -107,8 +109,7 @@ static int do_getsockopt(struct ip_set_req_get_set *req) if (size != sizeof(struct ip_set_req_get_set)) { fprintf(stderr, - "Incorrect return size from kernel during ipset lookup, " - "(want %zu, got %zu)\n", + "Incorrect return size from kernel during ipset lookup, (want %zu, got %zu)\n", sizeof(struct ip_set_req_get_set), (size_t)size); return -1; } @@ -144,8 +145,7 @@ get_set_byname(const char *setname, struct xt_set_info *info) int res; req.op = IP_SET_OP_GET_BYNAME; - strncpy(req.set.name, setname, IPSET_MAXNAMELEN); - req.set.name[IPSET_MAXNAMELEN - 1] = '\0'; + strlcpy(req.set.name, setname, IPSET_MAXNAMELEN); res = do_getsockopt(&req); if (res != 0) return -1; @@ -158,29 +158,29 @@ get_set_byname(const char *setname, struct xt_set_info *info) static int parse_dirs(const char *opt_arg, struct xt_set_info *info) { - char *saved = strdup(opt_arg); - char *ptr, *tmp = saved; + char *saved = strdup(opt_arg); + char *ptr, *tmp = saved; if (!tmp) { perror("strdup"); return -1; } - while (info->dim < IPSET_DIM_MAX && tmp != NULL) { - info->dim++; - ptr = strsep(&tmp, ","); - if (strncmp(ptr, "src", 3) == 0) - info->flags |= (1 << info->dim); - else if (strncmp(ptr, "dst", 3) != 0) { - fputs("You must specify (the comma separated list of) 'src' or 'dst'\n", stderr); + while (info->dim < IPSET_DIM_MAX && tmp != NULL) { + info->dim++; + ptr = strsep(&tmp, ","); + if (strncmp(ptr, "src", 3) == 0) + info->flags |= (1 << info->dim); + else if (strncmp(ptr, "dst", 3) != 0) { + fputs("You must specify (the comma separated list of) 'src' or 'dst'\n", stderr); free(saved); return -1; } - } + } - if (tmp) - fprintf(stderr, "Can't be more src/dst options than %u", IPSET_DIM_MAX); - free(saved); + if (tmp) + fprintf(stderr, "Can't be more src/dst options than %u", IPSET_DIM_MAX); + free(saved); return tmp ? -1 : 0; } @@ -198,13 +198,11 @@ static void ipset_print_usage(FILE *fd) static int ipset_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *args) { - struct xt_set_info set_info; + struct xt_set_info set_info = {}; int ret; - memset(&set_info, 0, sizeof(set_info)); - #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &ipset_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &ipset_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "ipset: missing set name"); @@ -238,7 +236,7 @@ static int ipset_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, int data_len) { int i; - char setname[IPSET_MAXNAMELEN]; + char setname[IPSET_MAXNAMELEN]; const struct xt_set_info *set_info = data; if (data_len != sizeof(*set_info)) { @@ -246,7 +244,7 @@ static int ipset_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, return -1; } - if (get_set_byid(setname, set_info->index)) + if (get_set_byid(setname, set_info->index)) return -1; fputs(setname, fd); for (i = 1; i <= set_info->dim; i++) { diff --git a/tc/em_meta.c b/tc/em_meta.c index b64f333e..bf470937 100644 --- a/tc/em_meta.c +++ b/tc/em_meta.c @@ -41,9 +41,9 @@ static void meta_print_usage(FILE *fd) struct meta_entry { int id; - char * kind; - char * mask; - char * desc; + char *kind; + char *mask; + char *desc; } meta_table[] = { #define TCF_META_ID_SECTION 0 #define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc } @@ -102,7 +102,7 @@ struct meta_entry { __A(SK_RMEM_ALLOC, "sk_rmem", "i", "RMEM"), __A(SK_WMEM_ALLOC, "sk_wmem", "i", "WMEM"), __A(SK_OMEM_ALLOC, "sk_omem", "i", "OMEM"), - __A(SK_WMEM_QUEUED, "sk_wmem_queue","i", "WMEM queue"), + __A(SK_WMEM_QUEUED, "sk_wmem_queue", "i", "WMEM queue"), __A(SK_SND_QLEN, "sk_snd_queue", "i", "Send queue length"), __A(SK_RCV_QLEN, "sk_rcv_queue", "i", "Receive queue length"), __A(SK_ERR_QLEN, "sk_err_queue", "i", "Error queue length"), @@ -122,11 +122,11 @@ static inline int map_type(char k) return INT_MAX; } -static struct meta_entry * lookup_meta_entry(struct bstr *kind) +static struct meta_entry *lookup_meta_entry(struct bstr *kind) { int i; - for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) + for (i = 0; i < ARRAY_SIZE(meta_table); i++) if (!bstrcmp(kind, meta_table[i].kind) && meta_table[i].id != 0) return &meta_table[i]; @@ -134,11 +134,11 @@ static struct meta_entry * lookup_meta_entry(struct bstr *kind) return NULL; } -static struct meta_entry * lookup_meta_entry_byid(int id) +static struct meta_entry *lookup_meta_entry_byid(int id) { int i; - for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) + for (i = 0; i < ARRAY_SIZE(meta_table); i++) if (meta_table[i].id == id) return &meta_table[i]; @@ -159,6 +159,7 @@ static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val, case TCF_META_TYPE_VAR: if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) { struct bstr *a = (struct bstr *) val; + addattr_l(n, MAX_MSG, tlv, a->data, a->len); } break; @@ -192,7 +193,7 @@ static void list_meta_ids(FILE *fd) " ID Type Description\n" \ "--------------------------------------------------------"); - for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) { + for (i = 0; i < ARRAY_SIZE(meta_table); i++) { if (meta_table[i].id == TCF_META_ID_SECTION) { fprintf(fd, "\n%s:\n", meta_table[i].kind); } else { @@ -231,7 +232,7 @@ static void list_meta_ids(FILE *fd) #define PARSE_FAILURE ((void *) (-1)) #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT, ##ARGS) static inline int can_adopt(struct tcf_meta_val *val) { @@ -308,7 +309,7 @@ compatible: a = bstr_next(arg); - while(a) { + while (a) { if (!bstrcmp(a, "shift")) { unsigned long shift; @@ -360,11 +361,9 @@ static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, { int opnd; struct bstr *a; - struct tcf_meta_hdr meta_hdr; + struct tcf_meta_hdr meta_hdr = {}; unsigned long lvalue = 0, rvalue = 0; - memset(&meta_hdr, 0, sizeof(meta_hdr)); - if (args == NULL) return PARSE_ERR(args, "meta: missing arguments"); @@ -441,7 +440,7 @@ static inline int print_value(FILE *fd, int type, struct rtattr *rta) return -1; } - switch(type) { + switch (type) { case TCF_META_TYPE_INT: if (RTA_PAYLOAD(rta) < sizeof(__u32)) { fprintf(stderr, "meta int type value TLV " \ @@ -484,8 +483,9 @@ static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta) if (RTA_PAYLOAD(rta) < sizeof(__u32)) goto size_mismatch; - fprintf(fd, " mask 0x%08x", - rta_getattr_u32(rta)); + if (rta_getattr_u32(rta)) + fprintf(fd, " mask 0x%08x", + rta_getattr_u32(rta)); } break; } diff --git a/tc/em_nbyte.c b/tc/em_nbyte.c index 87f3e9d2..52b4d10a 100644 --- a/tc/em_nbyte.c +++ b/tc/em_nbyte.c @@ -44,12 +44,10 @@ static int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *needle = args; unsigned long offset = 0, layer = TCF_LAYER_NETWORK; int offset_present = 0; - struct tcf_em_nbyte nb; - - memset(&nb, 0, sizeof(nb)); + struct tcf_em_nbyte nb = {}; #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "nbyte: missing arguments"); diff --git a/tc/em_u32.c b/tc/em_u32.c index 21ed70fd..869ebde0 100644 --- a/tc/em_u32.c +++ b/tc/em_u32.c @@ -39,12 +39,10 @@ static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *a; int align, nh_len; unsigned long key, mask, offmask = 0, offset; - struct tc_u32_key u_key; - - memset(&u_key, 0, sizeof(u_key)); + struct tc_u32_key u_key = {}; #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "u32: missing arguments"); @@ -85,6 +83,7 @@ static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, nh_len = strlen("nexthdr+"); if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) { char buf[a->len - nh_len + 1]; + offmask = -1; memcpy(buf, a->data + nh_len, a->len - nh_len); offset = strtoul(buf, NULL, 0); diff --git a/tc/f_basic.c b/tc/f_basic.c index 4adf1d22..8370ea60 100644 --- a/tc/f_basic.c +++ b/tc/f_basic.c @@ -27,7 +27,7 @@ static void explain(void) { - fprintf(stderr, "Usage: ... basic [ match EMATCH_TREE ] \n"); + fprintf(stderr, "Usage: ... basic [ match EMATCH_TREE ]\n"); fprintf(stderr, " [ action ACTION_SPEC ] [ classid CLASSID ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); @@ -56,7 +56,7 @@ static int basic_parse_opt(struct filter_util *qu, char *handle, if (argc == 0) return 0; - tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len)); + tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); while (argc > 0) { @@ -69,7 +69,8 @@ static int basic_parse_opt(struct filter_util *qu, char *handle, continue; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -102,7 +103,7 @@ static int basic_parse_opt(struct filter_util *qu, char *handle, argc--; argv++; } - tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail; + tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; return 0; } @@ -134,7 +135,7 @@ static int basic_print_opt(struct filter_util *qu, FILE *f, } if (tb[TCA_BASIC_ACT]) { - tc_print_action(f, tb[TCA_BASIC_ACT]); + tc_print_action(f, tb[TCA_BASIC_ACT], 0); } return 0; @@ -6,7 +6,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Authors: Daniel Borkmann <dborkman@redhat.com> + * Authors: Daniel Borkmann <daniel@iogearbox.net> */ #include <stdio.h> @@ -15,18 +15,12 @@ #include <linux/bpf.h> #include "utils.h" + #include "tc_util.h" -#include "tc_bpf.h" +#include "bpf_util.h" static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_CLS; -static const int nla_tbl[BPF_NLA_MAX] = { - [BPF_NLA_OPS_LEN] = TCA_BPF_OPS_LEN, - [BPF_NLA_OPS] = TCA_BPF_OPS, - [BPF_NLA_FD] = TCA_BPF_FD, - [BPF_NLA_NAME] = TCA_BPF_NAME, -}; - static void explain(void) { fprintf(stderr, "Usage: ... bpf ...\n"); @@ -37,8 +31,8 @@ static void explain(void) fprintf(stderr, "\n"); fprintf(stderr, "eBPF use case:\n"); fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]"); - fprintf(stderr, " [ verbose ] [ direct-action ]\n"); - fprintf(stderr, " object-pinned FILE [ direct-action ]\n"); + fprintf(stderr, " [ verbose ] [ direct-action ] [ skip_hw | skip_sw ]\n"); + fprintf(stderr, " object-pinned FILE [ direct-action ] [ skip_hw | skip_sw ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Common remaining options:\n"); fprintf(stderr, " [ action ACTION_SPEC ]\n"); @@ -52,7 +46,7 @@ static void explain(void) fprintf(stderr, "pinned eBPF program.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where CLS_NAME refers to the section name containing the\n"); - fprintf(stderr, "classifier (default \'%s\').\n", bpf_default_section(bpf_type)); + fprintf(stderr, "classifier (default \'%s\').\n", bpf_prog_to_default_section(bpf_type)); fprintf(stderr, "\n"); fprintf(stderr, "Where UDS_FILE points to a unix domain socket file in order\n"); fprintf(stderr, "to hand off control of all created eBPF maps to an agent.\n"); @@ -61,19 +55,36 @@ static void explain(void) fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n"); } +static void bpf_cbpf_cb(void *nl, const struct sock_filter *ops, int ops_len) +{ + addattr16(nl, MAX_MSG, TCA_BPF_OPS_LEN, ops_len); + addattr_l(nl, MAX_MSG, TCA_BPF_OPS, ops, + ops_len * sizeof(struct sock_filter)); +} + +static void bpf_ebpf_cb(void *nl, int fd, const char *annotation) +{ + addattr32(nl, MAX_MSG, TCA_BPF_FD, fd); + addattrstrz(nl, MAX_MSG, TCA_BPF_NAME, annotation); +} + +static const struct bpf_cfg_ops bpf_cb_ops = { + .cbpf_cb = bpf_cbpf_cb, + .ebpf_cb = bpf_ebpf_cb, +}; + static int bpf_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { const char *bpf_obj = NULL, *bpf_uds_name = NULL; struct tcmsg *t = NLMSG_DATA(n); + unsigned int bpf_gen_flags = 0; unsigned int bpf_flags = 0; + struct bpf_cfg_in cfg = {}; bool seen_run = false; struct rtattr *tail; int ret = 0; - if (argc == 0) - return 0; - if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); @@ -81,6 +92,9 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, } } + if (argc == 0) + return 0; + tail = (struct rtattr *)(((void *)n) + NLMSG_ALIGN(n->nlmsg_len)); addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); @@ -89,11 +103,17 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, NEXT_ARG(); opt_bpf: seen_run = true; - if (bpf_parse_common(&argc, &argv, nla_tbl, bpf_type, - &bpf_obj, &bpf_uds_name, n)) { - fprintf(stderr, "Failed to retrieve (e)BPF data!\n"); + cfg.argc = argc; + cfg.argv = argv; + + if (bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, n)) return -1; - } + + argc = cfg.argc; + argv = cfg.argv; + + bpf_obj = cfg.object; + bpf_uds_name = cfg.uds; } else if (matches(*argv, "classid") == 0 || matches(*argv, "flowid") == 0) { unsigned int handle; @@ -107,6 +127,10 @@ opt_bpf: } else if (matches(*argv, "direct-action") == 0 || matches(*argv, "da") == 0) { bpf_flags |= TCA_BPF_FLAG_ACT_DIRECT; + } else if (matches(*argv, "skip_hw") == 0) { + bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_HW; + } else if (matches(*argv, "skip_sw") == 0) { + bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_SW; } else if (matches(*argv, "action") == 0) { NEXT_ARG(); if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) { @@ -136,7 +160,9 @@ opt_bpf: NEXT_ARG_FWD(); } - if (bpf_obj && bpf_flags) + if (bpf_gen_flags) + addattr32(n, MAX_MSG, TCA_BPF_FLAGS_GEN, bpf_gen_flags); + if (bpf_flags) addattr32(n, MAX_MSG, TCA_BPF_FLAGS, bpf_flags); tail->rta_len = (((void *)n) + n->nlmsg_len) - (void *)tail; @@ -151,6 +177,7 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle) { struct rtattr *tb[TCA_BPF_MAX + 1]; + int dump_ok = 0; if (opt == NULL) return 0; @@ -168,8 +195,6 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f, if (tb[TCA_BPF_NAME]) fprintf(f, "%s ", rta_getattr_str(tb[TCA_BPF_NAME])); - else if (tb[TCA_BPF_FD]) - fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_BPF_FD])); if (tb[TCA_BPF_FLAGS]) { unsigned int flags = rta_getattr_u32(tb[TCA_BPF_FLAGS]); @@ -178,10 +203,34 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f, fprintf(f, "direct-action "); } - if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN]) { + if (tb[TCA_BPF_FLAGS_GEN]) { + unsigned int flags = + rta_getattr_u32(tb[TCA_BPF_FLAGS_GEN]); + + if (flags & TCA_CLS_FLAGS_SKIP_HW) + fprintf(f, "skip_hw "); + if (flags & TCA_CLS_FLAGS_SKIP_SW) + fprintf(f, "skip_sw "); + + if (flags & TCA_CLS_FLAGS_IN_HW) + fprintf(f, "in_hw "); + else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) + fprintf(f, "not_in_hw "); + } + + if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN]) bpf_print_ops(f, tb[TCA_BPF_OPS], rta_getattr_u16(tb[TCA_BPF_OPS_LEN])); - fprintf(f, "\n"); + + if (tb[TCA_BPF_ID]) + dump_ok = bpf_dump_prog_info(f, rta_getattr_u32(tb[TCA_BPF_ID])); + if (!dump_ok && tb[TCA_BPF_TAG]) { + SPRINT_BUF(b); + + fprintf(f, "tag %s ", + hexstring_n2a(RTA_DATA(tb[TCA_BPF_TAG]), + RTA_PAYLOAD(tb[TCA_BPF_TAG]), + b, sizeof(b))); } if (tb[TCA_BPF_POLICE]) { @@ -189,9 +238,8 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f, tc_print_police(f, tb[TCA_BPF_POLICE]); } - if (tb[TCA_BPF_ACT]) { - tc_print_action(f, tb[TCA_BPF_ACT]); - } + if (tb[TCA_BPF_ACT]) + tc_print_action(f, tb[TCA_BPF_ACT], 0); return 0; } diff --git a/tc/f_cgroup.c b/tc/f_cgroup.c index 53f7406f..633700e6 100644 --- a/tc/f_cgroup.c +++ b/tc/f_cgroup.c @@ -40,7 +40,7 @@ static int cgroup_parse_opt(struct filter_util *qu, char *handle, t->tcm_handle = h; - tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len)); + tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); while (argc > 0) { @@ -76,7 +76,7 @@ static int cgroup_parse_opt(struct filter_util *qu, char *handle, } } - tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail; + tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; return 0; } @@ -102,7 +102,7 @@ static int cgroup_print_opt(struct filter_util *qu, FILE *f, } if (tb[TCA_CGROUP_ACT]) - tc_print_action(f, tb[TCA_CGROUP_ACT]); + tc_print_action(f, tb[TCA_CGROUP_ACT], 0); return 0; } diff --git a/tc/f_flow.c b/tc/f_flow.c index f398f55b..b1571049 100644 --- a/tc/f_flow.c +++ b/tc/f_flow.c @@ -30,8 +30,8 @@ static void explain(void) " [ action ACTION_SPEC ]\n" "\n" "KEY-LIST := [ KEY-LIST , ] KEY\n" -"KEY := [ src | dst | proto | proto-src | proto-dst | iif | priority | \n" -" mark | nfct | nfct-src | nfct-dst | nfct-proto-src | \n" +"KEY := [ src | dst | proto | proto-src | proto-dst | iif | priority |\n" +" mark | nfct | nfct-src | nfct-dst | nfct-proto-src |\n" " nfct-proto-dst | rt-classid | sk-uid | sk-gid |\n" " vlan-tag | rxhash ]\n" "OPS := [ or NUM | and NUM | xor NUM | rshift NUM | addend NUM ]\n" @@ -133,7 +133,6 @@ out: static int flow_parse_opt(struct filter_util *fu, char *handle, int argc, char **argv, struct nlmsghdr *n) { - struct tc_police tp; struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __u32 mask = ~0U, xor = 0; @@ -141,8 +140,6 @@ static int flow_parse_opt(struct filter_util *fu, char *handle, __u32 mode = FLOW_MODE_MAP; __u32 tmp; - memset(&tp, 0, sizeof(tp)); - if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); @@ -270,6 +267,7 @@ static int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt, __u32 handle) { struct rtattr *tb[TCA_FLOW_MAX+1]; + SPRINT_BUF(b1); unsigned int i; __u32 mask = ~0, val = 0; @@ -349,7 +347,7 @@ static int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt, tc_print_police(f, tb[TCA_FLOW_POLICE]); if (tb[TCA_FLOW_ACT]) { fprintf(f, "\n"); - tc_print_action(f, tb[TCA_FLOW_ACT]); + tc_print_action(f, tb[TCA_FLOW_ACT], 0); } return 0; } diff --git a/tc/f_flower.c b/tc/f_flower.c index db9cc296..b1802107 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -15,48 +15,184 @@ #include <syslog.h> #include <string.h> #include <net/if.h> +#include <linux/if_arp.h> #include <linux/if_ether.h> #include <linux/ip.h> +#include <linux/tc_act/tc_vlan.h> #include "utils.h" #include "tc_util.h" #include "rt_names.h" +enum flower_matching_flags { + FLOWER_IP_FLAGS, +}; + +enum flower_endpoint { + FLOWER_ENDPOINT_SRC, + FLOWER_ENDPOINT_DST +}; + +enum flower_icmp_field { + FLOWER_ICMP_FIELD_TYPE, + FLOWER_ICMP_FIELD_CODE +}; + static void explain(void) { - fprintf(stderr, "Usage: ... flower [ MATCH-LIST ]\n"); - fprintf(stderr, " [ action ACTION-SPEC ] [ classid CLASSID ]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"); - fprintf(stderr, " MATCH := { indev DEV-NAME | \n"); - fprintf(stderr, " dst_mac MAC-ADDR | \n"); - fprintf(stderr, " src_mac MAC-ADDR | \n"); - fprintf(stderr, " [ipv4 | ipv6 ] | \n"); - fprintf(stderr, " ip_proto [tcp | udp | IP-PROTO ] | \n"); - fprintf(stderr, " dst_ip [ IPV4-ADDR | IPV6-ADDR ] | \n"); - fprintf(stderr, " src_ip [ IPV4-ADDR | IPV6-ADDR ] | \n"); - fprintf(stderr, " dst_port PORT-NUMBER | \n"); - fprintf(stderr, " src_port PORT-NUMBER }\n"); - fprintf(stderr, " FILTERID := X:Y:Z\n"); - fprintf(stderr, " ACTION-SPEC := ... look at individual actions\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "NOTE: CLASSID, ETH-TYPE, IP-PROTO are parsed as hexadecimal input.\n"); - fprintf(stderr, "NOTE: There can be only used one mask per one prio. If user needs\n"); - fprintf(stderr, " to specify different mask, he has to use different prio.\n"); + fprintf(stderr, + "Usage: ... flower [ MATCH-LIST ]\n" + " [ skip_sw | skip_hw ]\n" + " [ action ACTION-SPEC ] [ classid CLASSID ]\n" + "\n" + "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n" + " MATCH := { indev DEV-NAME |\n" + " vlan_id VID |\n" + " vlan_prio PRIORITY |\n" + " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n" + " dst_mac MASKED-LLADDR |\n" + " src_mac MASKED-LLADDR |\n" + " ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n" + " ip_tos MASKED-IP_TOS |\n" + " ip_ttl MASKED-IP_TTL |\n" + " dst_ip PREFIX |\n" + " src_ip PREFIX |\n" + " dst_port PORT-NUMBER |\n" + " src_port PORT-NUMBER |\n" + " tcp_flags MASKED-TCP_FLAGS |\n" + " type MASKED-ICMP-TYPE |\n" + " code MASKED-ICMP-CODE |\n" + " arp_tip IPV4-PREFIX |\n" + " arp_sip IPV4-PREFIX |\n" + " arp_op [ request | reply | OP ] |\n" + " arp_tha MASKED-LLADDR |\n" + " arp_sha MASKED-LLADDR |\n" + " enc_dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n" + " enc_src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n" + " enc_key_id [ KEY-ID ] |\n" + " ip_flags IP-FLAGS | \n" + " enc_dst_port [ port_number ] }\n" + " FILTERID := X:Y:Z\n" + " MASKED_LLADDR := { LLADDR | LLADDR/MASK | LLADDR/BITS }\n" + " ACTION-SPEC := ... look at individual actions\n" + "\n" + "NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n" + "NOTE: There can be only used one mask per one prio. If user needs\n" + " to specify different mask, he has to use different prio.\n"); } static int flower_parse_eth_addr(char *str, int addr_type, int mask_type, struct nlmsghdr *n) { - int ret; - char addr[ETH_ALEN]; + int ret, err = -1; + char addr[ETH_ALEN], *slash; + + slash = strchr(str, '/'); + if (slash) + *slash = '\0'; ret = ll_addr_a2n(addr, sizeof(addr), str); if (ret < 0) - return -1; + goto err; addattr_l(n, MAX_MSG, addr_type, addr, sizeof(addr)); - memset(addr, 0xff, ETH_ALEN); + + if (slash) { + unsigned bits; + + if (!get_unsigned(&bits, slash + 1, 10)) { + uint64_t mask; + + /* Extra 16 bit shift to push mac address into + * high bits of uint64_t + */ + mask = htonll(0xffffffffffffULL << (16 + 48 - bits)); + memcpy(addr, &mask, ETH_ALEN); + } else { + ret = ll_addr_a2n(addr, sizeof(addr), slash + 1); + if (ret < 0) + goto err; + } + } else { + memset(addr, 0xff, ETH_ALEN); + } addattr_l(n, MAX_MSG, mask_type, addr, sizeof(addr)); + + err = 0; +err: + if (slash) + *slash = '/'; + return err; +} + +static int flower_parse_vlan_eth_type(char *str, __be16 eth_type, int type, + __be16 *p_vlan_eth_type, + struct nlmsghdr *n) +{ + __be16 vlan_eth_type; + + if (eth_type != htons(ETH_P_8021Q)) { + fprintf(stderr, + "Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n"); + return -1; + } + + if (ll_proto_a2n(&vlan_eth_type, str)) + invarg("invalid vlan_ethtype", str); + addattr16(n, MAX_MSG, type, vlan_eth_type); + *p_vlan_eth_type = vlan_eth_type; + return 0; +} + +struct flag_to_string { + int flag; + enum flower_matching_flags type; + char *string; +}; + +static struct flag_to_string flags_str[] = { + { TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOWER_IP_FLAGS, "frag" }, +}; + +static int flower_parse_matching_flags(char *str, + enum flower_matching_flags type, + __u32 *mtf, __u32 *mtf_mask) +{ + char *token; + bool no; + bool found; + int i; + + token = strtok(str, "/"); + + while (token) { + if (!strncmp(token, "no", 2)) { + no = true; + token += 2; + } else + no = false; + + found = false; + for (i = 0; i < ARRAY_SIZE(flags_str); i++) { + if (type != flags_str[i].type) + continue; + + if (!strcmp(token, flags_str[i].string)) { + if (no) + *mtf &= ~flags_str[i].flag; + else + *mtf |= flags_str[i].flag; + + *mtf_mask |= flags_str[i].flag; + found = true; + break; + } + } + if (!found) + return -1; + + token = strtok(NULL, "/"); + } + return 0; } @@ -66,14 +202,23 @@ static int flower_parse_ip_proto(char *str, __be16 eth_type, int type, int ret; __u8 ip_proto; - if (eth_type != htons(ETH_P_IP) && eth_type != htons(ETH_P_IPV6)) { - fprintf(stderr, "Illegal \"eth_type\" for ip proto\n"); - return -1; - } + if (eth_type != htons(ETH_P_IP) && eth_type != htons(ETH_P_IPV6)) + goto err; + if (matches(str, "tcp") == 0) { ip_proto = IPPROTO_TCP; } else if (matches(str, "udp") == 0) { ip_proto = IPPROTO_UDP; + } else if (matches(str, "sctp") == 0) { + ip_proto = IPPROTO_SCTP; + } else if (matches(str, "icmp") == 0) { + if (eth_type != htons(ETH_P_IP)) + goto err; + ip_proto = IPPROTO_ICMP; + } else if (matches(str, "icmpv6") == 0) { + if (eth_type != htons(ETH_P_IPV6)) + goto err; + ip_proto = IPPROTO_ICMPV6; } else { ret = get_u8(&ip_proto, str, 16); if (ret) @@ -82,34 +227,30 @@ static int flower_parse_ip_proto(char *str, __be16 eth_type, int type, addattr8(n, MAX_MSG, type, ip_proto); *p_ip_proto = ip_proto; return 0; + +err: + fprintf(stderr, "Illegal \"eth_type\" for ip proto\n"); + return -1; } -static int flower_parse_ip_addr(char *str, __be16 eth_type, - int addr4_type, int mask4_type, - int addr6_type, int mask6_type, - struct nlmsghdr *n) +static int __flower_parse_ip_addr(char *str, int family, + int addr4_type, int mask4_type, + int addr6_type, int mask6_type, + struct nlmsghdr *n) { int ret; inet_prefix addr; - int family; int bits; int i; - if (eth_type == htons(ETH_P_IP)) { - family = AF_INET; - } else if (eth_type == htons(ETH_P_IPV6)) { - family = AF_INET6; - } else { - fprintf(stderr, "Illegal \"eth_type\" for ip address\n"); - return -1; - } - ret = get_prefix(&addr, str, family); if (ret) return -1; - if (addr.family != family) + if (family && (addr.family != family)) { + fprintf(stderr, "Illegal \"eth_type\" for ip address\n"); return -1; + } addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type, addr.data, addr.bytelen); @@ -134,27 +275,300 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type, return 0; } -static int flower_parse_port(char *str, __u8 ip_port, - int tcp_type, int udp_type, struct nlmsghdr *n) +static int flower_parse_ip_addr(char *str, __be16 eth_type, + int addr4_type, int mask4_type, + int addr6_type, int mask6_type, + struct nlmsghdr *n) +{ + int family; + + if (eth_type == htons(ETH_P_IP)) { + family = AF_INET; + } else if (eth_type == htons(ETH_P_IPV6)) { + family = AF_INET6; + } else if (!eth_type) { + family = AF_UNSPEC; + } else { + return -1; + } + + return __flower_parse_ip_addr(str, family, addr4_type, mask4_type, + addr6_type, mask6_type, n); +} + +static bool flower_eth_type_arp(__be16 eth_type) +{ + return eth_type == htons(ETH_P_ARP) || eth_type == htons(ETH_P_RARP); +} + +static int flower_parse_arp_ip_addr(char *str, __be16 eth_type, + int addr_type, int mask_type, + struct nlmsghdr *n) +{ + if (!flower_eth_type_arp(eth_type)) + return -1; + + return __flower_parse_ip_addr(str, AF_INET, addr_type, mask_type, + TCA_FLOWER_UNSPEC, TCA_FLOWER_UNSPEC, n); +} + +static int flower_parse_u8(char *str, int value_type, int mask_type, + int (*value_from_name)(const char *str, + __u8 *value), + bool (*value_validate)(__u8 value), + struct nlmsghdr *n) +{ + char *slash; + int ret, err = -1; + __u8 value, mask; + + slash = strchr(str, '/'); + if (slash) + *slash = '\0'; + + ret = value_from_name ? value_from_name(str, &value) : -1; + if (ret < 0) { + ret = get_u8(&value, str, 10); + if (ret) + goto err; + } + + if (value_validate && !value_validate(value)) + goto err; + + if (slash) { + ret = get_u8(&mask, slash + 1, 10); + if (ret) + goto err; + } + else { + mask = UINT8_MAX; + } + + addattr8(n, MAX_MSG, value_type, value); + addattr8(n, MAX_MSG, mask_type, mask); + + err = 0; +err: + if (slash) + *slash = '/'; + return err; +} + +static const char *flower_print_arp_op_to_name(__u8 op) +{ + switch (op) { + case ARPOP_REQUEST: + return "request"; + case ARPOP_REPLY: + return "reply"; + default: + return NULL; + } +} + +static int flower_arp_op_from_name(const char *name, __u8 *op) +{ + if (!strcmp(name, "request")) + *op = ARPOP_REQUEST; + else if (!strcmp(name, "reply")) + *op = ARPOP_REPLY; + else + return -1; + + return 0; +} + +static bool flow_arp_op_validate(__u8 op) +{ + return !op || op == ARPOP_REQUEST || op == ARPOP_REPLY; +} + +static int flower_parse_arp_op(char *str, __be16 eth_type, + int op_type, int mask_type, + struct nlmsghdr *n) +{ + if (!flower_eth_type_arp(eth_type)) + return -1; + + return flower_parse_u8(str, op_type, mask_type, flower_arp_op_from_name, + flow_arp_op_validate, n); +} + +static int flower_icmp_attr_type(__be16 eth_type, __u8 ip_proto, + enum flower_icmp_field field) +{ + if (eth_type == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP) + return field == FLOWER_ICMP_FIELD_CODE ? + TCA_FLOWER_KEY_ICMPV4_CODE : + TCA_FLOWER_KEY_ICMPV4_TYPE; + else if (eth_type == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6) + return field == FLOWER_ICMP_FIELD_CODE ? + TCA_FLOWER_KEY_ICMPV6_CODE : + TCA_FLOWER_KEY_ICMPV6_TYPE; + + return -1; +} + +static int flower_icmp_attr_mask_type(__be16 eth_type, __u8 ip_proto, + enum flower_icmp_field field) +{ + if (eth_type == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP) + return field == FLOWER_ICMP_FIELD_CODE ? + TCA_FLOWER_KEY_ICMPV4_CODE_MASK : + TCA_FLOWER_KEY_ICMPV4_TYPE_MASK; + else if (eth_type == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6) + return field == FLOWER_ICMP_FIELD_CODE ? + TCA_FLOWER_KEY_ICMPV6_CODE_MASK : + TCA_FLOWER_KEY_ICMPV6_TYPE_MASK; + + return -1; +} + +static int flower_parse_icmp(char *str, __u16 eth_type, __u8 ip_proto, + enum flower_icmp_field field, struct nlmsghdr *n) +{ + int value_type, mask_type; + + value_type = flower_icmp_attr_type(eth_type, ip_proto, field); + mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, field); + if (value_type < 0 || mask_type < 0) + return -1; + + return flower_parse_u8(str, value_type, mask_type, NULL, NULL, n); +} + +static int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint) +{ + if (ip_proto == IPPROTO_TCP) + return endpoint == FLOWER_ENDPOINT_SRC ? + TCA_FLOWER_KEY_TCP_SRC : + TCA_FLOWER_KEY_TCP_DST; + else if (ip_proto == IPPROTO_UDP) + return endpoint == FLOWER_ENDPOINT_SRC ? + TCA_FLOWER_KEY_UDP_SRC : + TCA_FLOWER_KEY_UDP_DST; + else if (ip_proto == IPPROTO_SCTP) + return endpoint == FLOWER_ENDPOINT_SRC ? + TCA_FLOWER_KEY_SCTP_SRC : + TCA_FLOWER_KEY_SCTP_DST; + else + return -1; +} + +static int flower_parse_port(char *str, __u8 ip_proto, + enum flower_endpoint endpoint, + struct nlmsghdr *n) { int ret; int type; __be16 port; - if (ip_port == IPPROTO_TCP) { - type = tcp_type; - } else if (ip_port == IPPROTO_UDP) { - type = udp_type; - } else { - fprintf(stderr, "Illegal \"ip_proto\" for port\n"); + type = flower_port_attr_type(ip_proto, endpoint); + if (type < 0) + return -1; + + ret = get_be16(&port, str, 10); + if (ret) return -1; + + addattr16(n, MAX_MSG, type, port); + + return 0; +} + +#define TCP_FLAGS_MAX_MASK 0xfff + +static int flower_parse_tcp_flags(char *str, int flags_type, int mask_type, + struct nlmsghdr *n) +{ + char *slash; + int ret, err = -1; + __u16 flags; + + slash = strchr(str, '/'); + if (slash) + *slash = '\0'; + + ret = get_u16(&flags, str, 16); + if (ret < 0 || flags & ~TCP_FLAGS_MAX_MASK) + goto err; + + addattr16(n, MAX_MSG, flags_type, htons(flags)); + + if (slash) { + ret = get_u16(&flags, slash + 1, 16); + if (ret < 0 || flags & ~TCP_FLAGS_MAX_MASK) + goto err; + } else { + flags = TCP_FLAGS_MAX_MASK; } + addattr16(n, MAX_MSG, mask_type, htons(flags)); + + err = 0; +err: + if (slash) + *slash = '/'; + return err; +} + +static int flower_parse_ip_tos_ttl(char *str, int key_type, int mask_type, + struct nlmsghdr *n) +{ + char *slash; + int ret, err = -1; + __u8 tos_ttl; + + slash = strchr(str, '/'); + if (slash) + *slash = '\0'; + + ret = get_u8(&tos_ttl, str, 10); + if (ret < 0) + ret = get_u8(&tos_ttl, str, 16); + if (ret < 0) + goto err; + + addattr8(n, MAX_MSG, key_type, tos_ttl); - ret = get_u16(&port, str, 10); + if (slash) { + ret = get_u8(&tos_ttl, slash + 1, 16); + if (ret < 0) + goto err; + } else { + tos_ttl = 0xff; + } + addattr8(n, MAX_MSG, mask_type, tos_ttl); + + err = 0; +err: + if (slash) + *slash = '/'; + return err; +} + +static int flower_parse_key_id(const char *str, int type, struct nlmsghdr *n) +{ + int ret; + __be32 key_id; + + ret = get_be32(&key_id, str, 10); + if (!ret) + addattr32(n, MAX_MSG, type, key_id); + + return ret; +} + +static int flower_parse_enc_port(char *str, int type, struct nlmsghdr *n) +{ + int ret; + __be16 port; + + ret = get_be16(&port, str, 10); if (ret) return -1; - addattr16(n, MAX_MSG, type, htons(port)); + addattr16(n, MAX_MSG, type, port); return 0; } @@ -166,7 +580,11 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __be16 eth_type = TC_H_MIN(t->tcm_info); + __be16 vlan_ethtype = 0; __u8 ip_proto = 0xff; + __u32 flags = 0; + __u32 mtf = 0; + __u32 mtf_mask = 0; if (handle) { ret = get_u32(&t->tcm_handle, handle, 0); @@ -187,7 +605,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, while (argc > 0) { if (matches(*argv, "classid") == 0 || matches(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; NEXT_ARG(); ret = get_tc_classid(&handle, *argv); @@ -196,13 +614,63 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, return -1; } addattr_l(n, MAX_MSG, TCA_FLOWER_CLASSID, &handle, 4); + } else if (matches(*argv, "ip_flags") == 0) { + NEXT_ARG(); + ret = flower_parse_matching_flags(*argv, + FLOWER_IP_FLAGS, + &mtf, + &mtf_mask); + if (ret < 0) { + fprintf(stderr, "Illegal \"ip_flags\"\n"); + return -1; + } + } else if (matches(*argv, "skip_hw") == 0) { + flags |= TCA_CLS_FLAGS_SKIP_HW; + } else if (matches(*argv, "skip_sw") == 0) { + flags |= TCA_CLS_FLAGS_SKIP_SW; } else if (matches(*argv, "indev") == 0) { - char ifname[IFNAMSIZ]; + NEXT_ARG(); + if (check_ifname(*argv)) + invarg("\"indev\" not a valid ifname", *argv); + addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, *argv); + } else if (matches(*argv, "vlan_id") == 0) { + __u16 vid; + + NEXT_ARG(); + if (eth_type != htons(ETH_P_8021Q)) { + fprintf(stderr, + "Can't set \"vlan_id\" if ethertype isn't 802.1Q\n"); + return -1; + } + ret = get_u16(&vid, *argv, 10); + if (ret < 0 || vid & ~0xfff) { + fprintf(stderr, "Illegal \"vlan_id\"\n"); + return -1; + } + addattr16(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_ID, vid); + } else if (matches(*argv, "vlan_prio") == 0) { + __u8 vlan_prio; NEXT_ARG(); - memset(ifname, 0, sizeof(ifname)); - strncpy(ifname, *argv, sizeof(ifname) - 1); - addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, ifname); + if (eth_type != htons(ETH_P_8021Q)) { + fprintf(stderr, + "Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n"); + return -1; + } + ret = get_u8(&vlan_prio, *argv, 10); + if (ret < 0 || vlan_prio & ~0x7) { + fprintf(stderr, "Illegal \"vlan_prio\"\n"); + return -1; + } + addattr8(n, MAX_MSG, + TCA_FLOWER_KEY_VLAN_PRIO, vlan_prio); + } else if (matches(*argv, "vlan_ethtype") == 0) { + NEXT_ARG(); + ret = flower_parse_vlan_eth_type(*argv, eth_type, + TCA_FLOWER_KEY_VLAN_ETH_TYPE, + &vlan_ethtype, n); + if (ret < 0) + return -1; } else if (matches(*argv, "dst_mac") == 0) { NEXT_ARG(); ret = flower_parse_eth_addr(*argv, @@ -225,16 +693,38 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } } else if (matches(*argv, "ip_proto") == 0) { NEXT_ARG(); - ret = flower_parse_ip_proto(*argv, eth_type, + ret = flower_parse_ip_proto(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IP_PROTO, &ip_proto, n); if (ret < 0) { fprintf(stderr, "Illegal \"ip_proto\"\n"); return -1; } + } else if (matches(*argv, "ip_tos") == 0) { + NEXT_ARG(); + ret = flower_parse_ip_tos_ttl(*argv, + TCA_FLOWER_KEY_IP_TOS, + TCA_FLOWER_KEY_IP_TOS_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"ip_tos\"\n"); + return -1; + } + } else if (matches(*argv, "ip_ttl") == 0) { + NEXT_ARG(); + ret = flower_parse_ip_tos_ttl(*argv, + TCA_FLOWER_KEY_IP_TTL, + TCA_FLOWER_KEY_IP_TTL_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"ip_ttl\"\n"); + return -1; + } } else if (matches(*argv, "dst_ip") == 0) { NEXT_ARG(); - ret = flower_parse_ip_addr(*argv, eth_type, + ret = flower_parse_ip_addr(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IPV4_DST, TCA_FLOWER_KEY_IPV4_DST_MASK, TCA_FLOWER_KEY_IPV6_DST, @@ -246,7 +736,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } } else if (matches(*argv, "src_ip") == 0) { NEXT_ARG(); - ret = flower_parse_ip_addr(*argv, eth_type, + ret = flower_parse_ip_addr(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IPV4_SRC, TCA_FLOWER_KEY_IPV4_SRC_MASK, TCA_FLOWER_KEY_IPV6_SRC, @@ -259,8 +750,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } else if (matches(*argv, "dst_port") == 0) { NEXT_ARG(); ret = flower_parse_port(*argv, ip_proto, - TCA_FLOWER_KEY_TCP_DST, - TCA_FLOWER_KEY_UDP_DST, n); + FLOWER_ENDPOINT_DST, n); if (ret < 0) { fprintf(stderr, "Illegal \"dst_port\"\n"); return -1; @@ -268,12 +758,130 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } else if (matches(*argv, "src_port") == 0) { NEXT_ARG(); ret = flower_parse_port(*argv, ip_proto, - TCA_FLOWER_KEY_TCP_SRC, - TCA_FLOWER_KEY_UDP_SRC, n); + FLOWER_ENDPOINT_SRC, n); if (ret < 0) { fprintf(stderr, "Illegal \"src_port\"\n"); return -1; } + } else if (matches(*argv, "tcp_flags") == 0) { + NEXT_ARG(); + ret = flower_parse_tcp_flags(*argv, + TCA_FLOWER_KEY_TCP_FLAGS, + TCA_FLOWER_KEY_TCP_FLAGS_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"tcp_flags\"\n"); + return -1; + } + } else if (matches(*argv, "type") == 0) { + NEXT_ARG(); + ret = flower_parse_icmp(*argv, eth_type, ip_proto, + FLOWER_ICMP_FIELD_TYPE, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"icmp type\"\n"); + return -1; + } + } else if (matches(*argv, "code") == 0) { + NEXT_ARG(); + ret = flower_parse_icmp(*argv, eth_type, ip_proto, + FLOWER_ICMP_FIELD_CODE, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"icmp code\"\n"); + return -1; + } + } else if (matches(*argv, "arp_tip") == 0) { + NEXT_ARG(); + ret = flower_parse_arp_ip_addr(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, + TCA_FLOWER_KEY_ARP_TIP, + TCA_FLOWER_KEY_ARP_TIP_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"arp_tip\"\n"); + return -1; + } + } else if (matches(*argv, "arp_sip") == 0) { + NEXT_ARG(); + ret = flower_parse_arp_ip_addr(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, + TCA_FLOWER_KEY_ARP_SIP, + TCA_FLOWER_KEY_ARP_SIP_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"arp_sip\"\n"); + return -1; + } + } else if (matches(*argv, "arp_op") == 0) { + NEXT_ARG(); + ret = flower_parse_arp_op(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, + TCA_FLOWER_KEY_ARP_OP, + TCA_FLOWER_KEY_ARP_OP_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"arp_op\"\n"); + return -1; + } + } else if (matches(*argv, "arp_tha") == 0) { + NEXT_ARG(); + ret = flower_parse_eth_addr(*argv, + TCA_FLOWER_KEY_ARP_THA, + TCA_FLOWER_KEY_ARP_THA_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"arp_tha\"\n"); + return -1; + } + } else if (matches(*argv, "arp_sha") == 0) { + NEXT_ARG(); + ret = flower_parse_eth_addr(*argv, + TCA_FLOWER_KEY_ARP_SHA, + TCA_FLOWER_KEY_ARP_SHA_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"arp_sha\"\n"); + return -1; + } + } else if (matches(*argv, "enc_dst_ip") == 0) { + NEXT_ARG(); + ret = flower_parse_ip_addr(*argv, 0, + TCA_FLOWER_KEY_ENC_IPV4_DST, + TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, + TCA_FLOWER_KEY_ENC_IPV6_DST, + TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"enc_dst_ip\"\n"); + return -1; + } + } else if (matches(*argv, "enc_src_ip") == 0) { + NEXT_ARG(); + ret = flower_parse_ip_addr(*argv, 0, + TCA_FLOWER_KEY_ENC_IPV4_SRC, + TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, + TCA_FLOWER_KEY_ENC_IPV6_SRC, + TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"enc_src_ip\"\n"); + return -1; + } + } else if (matches(*argv, "enc_key_id") == 0) { + NEXT_ARG(); + ret = flower_parse_key_id(*argv, + TCA_FLOWER_KEY_ENC_KEY_ID, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"enc_key_id\"\n"); + return -1; + } + } else if (matches(*argv, "enc_dst_port") == 0) { + NEXT_ARG(); + ret = flower_parse_enc_port(*argv, + TCA_FLOWER_KEY_ENC_UDP_DST_PORT, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"enc_dst_port\"\n"); + return -1; + } } else if (matches(*argv, "action") == 0) { NEXT_ARG(); ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n); @@ -294,14 +902,27 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } parse_done: - ret = addattr16(n, MAX_MSG, TCA_FLOWER_KEY_ETH_TYPE, eth_type); - if (ret) { - fprintf(stderr, "Illegal \"eth_type\"(0x%x)\n", - ntohs(eth_type)); - return -1; + ret = addattr32(n, MAX_MSG, TCA_FLOWER_FLAGS, flags); + if (ret) + return ret; + + if (mtf_mask) { + ret = addattr32(n, MAX_MSG, TCA_FLOWER_KEY_FLAGS, htonl(mtf)); + if (ret) + return ret; + + ret = addattr32(n, MAX_MSG, TCA_FLOWER_KEY_FLAGS_MASK, htonl(mtf_mask)); + if (ret) + return ret; } - tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail; + if (eth_type != htons(ETH_P_ALL)) { + ret = addattr16(n, MAX_MSG, TCA_FLOWER_KEY_ETH_TYPE, eth_type); + if (ret) + return ret; + } + + tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; return 0; } @@ -364,6 +985,10 @@ static void flower_print_eth_type(FILE *f, __be16 *p_eth_type, fprintf(f, "ipv4"); else if (eth_type == htons(ETH_P_IPV6)) fprintf(f, "ipv6"); + else if (eth_type == htons(ETH_P_ARP)) + fprintf(f, "arp"); + else if (eth_type == htons(ETH_P_RARP)) + fprintf(f, "rarp"); else fprintf(f, "%04x", ntohs(eth_type)); *p_eth_type = eth_type; @@ -383,18 +1008,69 @@ static void flower_print_ip_proto(FILE *f, __u8 *p_ip_proto, fprintf(f, "tcp"); else if (ip_proto == IPPROTO_UDP) fprintf(f, "udp"); + else if (ip_proto == IPPROTO_SCTP) + fprintf(f, "sctp"); + else if (ip_proto == IPPROTO_ICMP) + fprintf(f, "icmp"); + else if (ip_proto == IPPROTO_ICMPV6) + fprintf(f, "icmpv6"); else fprintf(f, "%02x", ip_proto); *p_ip_proto = ip_proto; } +static void flower_print_ip_attr(FILE *f, char *name, + struct rtattr *key_attr, + struct rtattr *mask_attr) +{ + if (!key_attr) + return; + + fprintf(f, "\n %s %x", name, rta_getattr_u8(key_attr)); + if (!mask_attr) + return; + fprintf(f, "/%x", rta_getattr_u8(mask_attr)); +} + +static void flower_print_matching_flags(FILE *f, char *name, + enum flower_matching_flags type, + struct rtattr *attr, + struct rtattr *mask_attr) +{ + int i; + int count = 0; + __u32 mtf; + __u32 mtf_mask; + + if (!mask_attr || RTA_PAYLOAD(mask_attr) != 4) + return; + + mtf = ntohl(rta_getattr_u32(attr)); + mtf_mask = ntohl(rta_getattr_u32(mask_attr)); + + for (i = 0; i < ARRAY_SIZE(flags_str); i++) { + if (type != flags_str[i].type) + continue; + if (mtf_mask & flags_str[i].flag) { + if (++count == 1) + fprintf(f, "\n %s ", name); + else + fprintf(f, "/"); + + if (mtf & flags_str[i].flag) + fprintf(f, "%s", flags_str[i].string); + else + fprintf(f, "no%s", flags_str[i].string); + } + } +} + static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, struct rtattr *addr4_attr, struct rtattr *mask4_attr, struct rtattr *addr6_attr, struct rtattr *mask6_attr) { - SPRINT_BUF(b1); struct rtattr *addr_attr; struct rtattr *mask_attr; int family; @@ -416,43 +1092,89 @@ static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, } if (!addr_attr || RTA_PAYLOAD(addr_attr) != len) return; - fprintf(f, "\n %s %s", name, rt_addr_n2a(family, - RTA_PAYLOAD(addr_attr), - RTA_DATA(addr_attr), - b1, sizeof(b1))); + fprintf(f, "\n %s %s", name, rt_addr_n2a_rta(family, addr_attr)); if (!mask_attr || RTA_PAYLOAD(mask_attr) != len) return; bits = __mask_bits(RTA_DATA(mask_attr), len); if (bits < 0) - fprintf(f, "/%s", rt_addr_n2a(family, - RTA_PAYLOAD(mask_attr), - RTA_DATA(mask_attr), - b1, sizeof(b1))); + fprintf(f, "/%s", rt_addr_n2a_rta(family, mask_attr)); else if (bits < len * 8) fprintf(f, "/%d", bits); } +static void flower_print_ip4_addr(FILE *f, char *name, + struct rtattr *addr_attr, + struct rtattr *mask_attr) +{ + return flower_print_ip_addr(f, name, htons(ETH_P_IP), + addr_attr, mask_attr, 0, 0); +} -static void flower_print_port(FILE *f, char *name, __u8 ip_proto, - struct rtattr *tcp_attr, - struct rtattr *udp_attr) +static void flower_print_port(FILE *f, char *name, struct rtattr *attr) { - struct rtattr *attr; + if (attr) + fprintf(f, "\n %s %d", name, rta_getattr_be16(attr)); +} - if (ip_proto == IPPROTO_TCP) - attr = tcp_attr; - else if (ip_proto == IPPROTO_UDP) - attr = udp_attr; - else +static void flower_print_tcp_flags(FILE *f, char *name, + struct rtattr *flags_attr, + struct rtattr *mask_attr) +{ + if (!flags_attr) return; + fprintf(f, "\n %s %x", name, rta_getattr_be16(flags_attr)); + if (!mask_attr) + return; + fprintf(f, "/%x", rta_getattr_be16(mask_attr)); +} + + +static void flower_print_key_id(FILE *f, const char *name, + struct rtattr *attr) +{ + if (attr) + fprintf(f, "\n %s %d", name, rta_getattr_be32(attr)); +} + +static void flower_print_masked_u8(FILE *f, const char *name, + struct rtattr *attr, + struct rtattr *mask_attr, + const char *(*value_to_str)(__u8 value)) +{ + const char *value_str = NULL; + __u8 value, mask; + if (!attr) return; - fprintf(f, "\n %s %d", name, ntohs(rta_getattr_u16(attr))); + + value = rta_getattr_u8(attr); + mask = mask_attr ? rta_getattr_u8(mask_attr) : UINT8_MAX; + if (mask == UINT8_MAX && value_to_str) + value_str = value_to_str(value); + + fprintf(f, "\n %s ", name); + + if (value_str) + fputs(value_str, f); + else + fprintf(f, "%d", value); + + if (mask != UINT8_MAX) + fprintf(f, "/%d", mask); +} + +static void flower_print_arp_op(FILE *f, const char *name, + struct rtattr *op_attr, + struct rtattr *mask_attr) +{ + flower_print_masked_u8(f, name, op_attr, mask_attr, + flower_print_arp_op_to_name); } static int flower_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle) { struct rtattr *tb[TCA_FLOWER_MAX + 1]; + int nl_type, nl_mask_type; __be16 eth_type = 0; __u8 ip_proto = 0xff; @@ -477,6 +1199,18 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, fprintf(f, "\n indev %s", rta_getattr_str(attr)); } + if (tb[TCA_FLOWER_KEY_VLAN_ID]) { + struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID]; + + fprintf(f, "\n vlan_id %d", rta_getattr_u16(attr)); + } + + if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) { + struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO]; + + fprintf(f, "\n vlan_prio %d", rta_getattr_u8(attr)); + } + flower_print_eth_addr(f, "dst_mac", tb[TCA_FLOWER_KEY_ETH_DST], tb[TCA_FLOWER_KEY_ETH_DST_MASK]); flower_print_eth_addr(f, "src_mac", tb[TCA_FLOWER_KEY_ETH_SRC], @@ -485,6 +1219,11 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, flower_print_eth_type(f, ð_type, tb[TCA_FLOWER_KEY_ETH_TYPE]); flower_print_ip_proto(f, &ip_proto, tb[TCA_FLOWER_KEY_IP_PROTO]); + flower_print_ip_attr(f, "ip_tos", tb[TCA_FLOWER_KEY_IP_TOS], + tb[TCA_FLOWER_KEY_IP_TOS_MASK]); + flower_print_ip_attr(f, "ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL], + tb[TCA_FLOWER_KEY_IP_TTL_MASK]); + flower_print_ip_addr(f, "dst_ip", eth_type, tb[TCA_FLOWER_KEY_IPV4_DST], tb[TCA_FLOWER_KEY_IPV4_DST_MASK], @@ -497,18 +1236,87 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, tb[TCA_FLOWER_KEY_IPV6_SRC], tb[TCA_FLOWER_KEY_IPV6_SRC_MASK]); - flower_print_port(f, "dst_port", ip_proto, - tb[TCA_FLOWER_KEY_TCP_DST], - tb[TCA_FLOWER_KEY_UDP_DST]); + nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_DST); + if (nl_type >= 0) + flower_print_port(f, "dst_port", tb[nl_type]); + nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_SRC); + if (nl_type >= 0) + flower_print_port(f, "src_port", tb[nl_type]); + + flower_print_tcp_flags(f, "tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS], + tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]); - flower_print_port(f, "src_port", ip_proto, - tb[TCA_FLOWER_KEY_TCP_SRC], - tb[TCA_FLOWER_KEY_UDP_SRC]); + nl_type = flower_icmp_attr_type(eth_type, ip_proto, + FLOWER_ICMP_FIELD_TYPE); + nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, + FLOWER_ICMP_FIELD_TYPE); + if (nl_type >= 0 && nl_mask_type >= 0) + flower_print_masked_u8(f, "icmp_type", tb[nl_type], + tb[nl_mask_type], NULL); - if (tb[TCA_FLOWER_ACT]) { - tc_print_action(f, tb[TCA_FLOWER_ACT]); + nl_type = flower_icmp_attr_type(eth_type, ip_proto, + FLOWER_ICMP_FIELD_CODE); + nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, + FLOWER_ICMP_FIELD_CODE); + if (nl_type >= 0 && nl_mask_type >= 0) + flower_print_masked_u8(f, "icmp_code", tb[nl_type], + tb[nl_mask_type], NULL); + + flower_print_ip4_addr(f, "arp_sip", tb[TCA_FLOWER_KEY_ARP_SIP], + tb[TCA_FLOWER_KEY_ARP_SIP_MASK]); + flower_print_ip4_addr(f, "arp_tip", tb[TCA_FLOWER_KEY_ARP_TIP], + tb[TCA_FLOWER_KEY_ARP_TIP_MASK]); + flower_print_arp_op(f, "arp_op", tb[TCA_FLOWER_KEY_ARP_OP], + tb[TCA_FLOWER_KEY_ARP_OP_MASK]); + flower_print_eth_addr(f, "arp_sha", tb[TCA_FLOWER_KEY_ARP_SHA], + tb[TCA_FLOWER_KEY_ARP_SHA_MASK]); + flower_print_eth_addr(f, "arp_tha", tb[TCA_FLOWER_KEY_ARP_THA], + tb[TCA_FLOWER_KEY_ARP_THA_MASK]); + + flower_print_ip_addr(f, "enc_dst_ip", + tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ? + htons(ETH_P_IP) : htons(ETH_P_IPV6), + tb[TCA_FLOWER_KEY_ENC_IPV4_DST], + tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK], + tb[TCA_FLOWER_KEY_ENC_IPV6_DST], + tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]); + + flower_print_ip_addr(f, "enc_src_ip", + tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ? + htons(ETH_P_IP) : htons(ETH_P_IPV6), + tb[TCA_FLOWER_KEY_ENC_IPV4_SRC], + tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK], + tb[TCA_FLOWER_KEY_ENC_IPV6_SRC], + tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]); + + flower_print_key_id(f, "enc_key_id", + tb[TCA_FLOWER_KEY_ENC_KEY_ID]); + + flower_print_port(f, "enc_dst_port", + tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]); + + flower_print_matching_flags(f, "ip_flags", + FLOWER_IP_FLAGS, + tb[TCA_FLOWER_KEY_FLAGS], + tb[TCA_FLOWER_KEY_FLAGS_MASK]); + + if (tb[TCA_FLOWER_FLAGS]) { + __u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]); + + if (flags & TCA_CLS_FLAGS_SKIP_HW) + fprintf(f, "\n skip_hw"); + if (flags & TCA_CLS_FLAGS_SKIP_SW) + fprintf(f, "\n skip_sw"); + + if (flags & TCA_CLS_FLAGS_IN_HW) + fprintf(f, "\n in_hw"); + else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) + fprintf(f, "\n not_in_hw"); } + if (tb[TCA_FLOWER_ACT]) + tc_print_action(f, tb[TCA_FLOWER_ACT], 0); + return 0; } @@ -25,24 +25,31 @@ static void explain(void) { - fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ action ACTION_SPEC ]\n"); - fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); - fprintf(stderr, " CLASSID := X:Y\n"); - fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); + fprintf(stderr, + "Usage: ... fw [ classid CLASSID ] [ indev DEV ] [ action ACTION_SPEC ]\n"); + fprintf(stderr, + " CLASSID := Push matching packets to the class identified by CLASSID with format X:Y\n"); + fprintf(stderr, + " CLASSID is parsed as hexadecimal input.\n"); + fprintf(stderr, + " DEV := specify device for incoming device classification.\n"); + fprintf(stderr, + " ACTION_SPEC := Apply an action on matching packets.\n"); + fprintf(stderr, + " NOTE: handle is represented as HANDLE[/FWMASK].\n"); + fprintf(stderr, " FWMASK is 0xffffffff by default.\n"); } static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { - struct tc_police tp; struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __u32 mask = 0; int mask_set = 0; - memset(&tp, 0, sizeof(tp)); - if (handle) { char *slash; + if ((slash = strchr(handle, '/')) != NULL) *slash = '\0'; if (get_u32(&t->tcm_handle, handle, 0)) { @@ -70,7 +77,8 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a while (argc > 0) { if (matches(*argv, "classid") == 0 || matches(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -92,15 +100,15 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a } continue; } else if (strcmp(*argv, "indev") == 0) { - char d[IFNAMSIZ+1]; - memset(d, 0, sizeof (d)); + char d[IFNAMSIZ+1] = {}; + argc--; argv++; if (argc < 1) { fprintf(stderr, "Illegal indev\n"); return -1; } - strncpy(d, *argv, sizeof (d) - 1); + strncpy(d, *argv, sizeof(d) - 1); addattr_l(n, MAX_MSG, TCA_FW_INDEV, d, strlen(d) + 1); } else if (strcmp(*argv, "help") == 0) { explain(); @@ -127,9 +135,10 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u if (handle || tb[TCA_FW_MASK]) { __u32 mark = 0, mask = 0; - if(handle) + + if (handle) mark = handle; - if(tb[TCA_FW_MASK] && + if (tb[TCA_FW_MASK] && (mask = rta_getattr_u32(tb[TCA_FW_MASK])) != 0xFFFFFFFF) fprintf(f, "handle 0x%x/0x%x ", mark, mask); else @@ -145,12 +154,13 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u tc_print_police(f, tb[TCA_FW_POLICE]); if (tb[TCA_FW_INDEV]) { struct rtattr *idev = tb[TCA_FW_INDEV]; - fprintf(f, "input dev %s ",rta_getattr_str(idev)); + + fprintf(f, "input dev %s ", rta_getattr_str(idev)); } if (tb[TCA_FW_ACT]) { fprintf(f, "\n"); - tc_print_action(f, tb[TCA_FW_ACT]); + tc_print_action(f, tb[TCA_FW_ACT], 0); } return 0; } diff --git a/tc/f_matchall.c b/tc/f_matchall.c new file mode 100644 index 00000000..d78660e7 --- /dev/null +++ b/tc/f_matchall.c @@ -0,0 +1,157 @@ +/* + * f_matchall.c Match-all Classifier + * + * This program is free software; you can distribute 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: Jiri Pirko <jiri@mellanox.com>, Yotam Gigi <yotamg@mellanox.com> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <linux/if.h> + +#include "utils.h" +#include "tc_util.h" + +static void explain(void) +{ + fprintf(stderr, "Usage: ... matchall [skip_sw | skip_hw]\n"); + fprintf(stderr, " [ action ACTION_SPEC ] [ classid CLASSID ]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); + fprintf(stderr, " FILTERID := X:Y:Z\n"); + fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); + fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); +} + +static int matchall_parse_opt(struct filter_util *qu, char *handle, + int argc, char **argv, struct nlmsghdr *n) +{ + struct tcmsg *t = NLMSG_DATA(n); + struct rtattr *tail; + __u32 flags = 0; + long h = 0; + + if (handle) { + h = strtol(handle, NULL, 0); + if (h == LONG_MIN || h == LONG_MAX) { + fprintf(stderr, "Illegal handle \"%s\", must be numeric.\n", + handle); + return -1; + } + } + t->tcm_handle = h; + + if (argc == 0) + return 0; + + tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); + addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); + + while (argc > 0) { + if (matches(*argv, "classid") == 0 || + strcmp(*argv, "flowid") == 0) { + unsigned int handle; + + NEXT_ARG(); + if (get_tc_classid(&handle, *argv)) { + fprintf(stderr, "Illegal \"classid\"\n"); + return -1; + } + addattr_l(n, MAX_MSG, TCA_MATCHALL_CLASSID, &handle, 4); + } else if (matches(*argv, "action") == 0) { + NEXT_ARG(); + if (parse_action(&argc, &argv, TCA_MATCHALL_ACT, n)) { + fprintf(stderr, "Illegal \"action\"\n"); + return -1; + } + continue; + + } else if (strcmp(*argv, "skip_hw") == 0) { + NEXT_ARG(); + flags |= TCA_CLS_FLAGS_SKIP_HW; + continue; + } else if (strcmp(*argv, "skip_sw") == 0) { + NEXT_ARG(); + flags |= TCA_CLS_FLAGS_SKIP_SW; + continue; + } else if (strcmp(*argv, "help") == 0) { + explain(); + return -1; + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + explain(); + return -1; + } + argc--; argv++; + } + + if (flags) { + if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | + TCA_CLS_FLAGS_SKIP_SW))) { + fprintf(stderr, + "skip_hw and skip_sw are mutually exclusive\n"); + return -1; + } + addattr_l(n, MAX_MSG, TCA_MATCHALL_FLAGS, &flags, 4); + } + + tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; + return 0; +} + +static int matchall_print_opt(struct filter_util *qu, FILE *f, + struct rtattr *opt, __u32 handle) +{ + struct rtattr *tb[TCA_MATCHALL_MAX+1]; + + if (opt == NULL) + return 0; + + parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt); + + if (handle) + fprintf(f, "handle 0x%x ", handle); + + if (tb[TCA_MATCHALL_CLASSID]) { + SPRINT_BUF(b1); + fprintf(f, "flowid %s ", + sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1)); + } + + if (tb[TCA_MATCHALL_FLAGS]) { + __u32 flags = rta_getattr_u32(tb[TCA_MATCHALL_FLAGS]); + + if (flags & TCA_CLS_FLAGS_SKIP_HW) + fprintf(f, "\n skip_hw"); + if (flags & TCA_CLS_FLAGS_SKIP_SW) + fprintf(f, "\n skip_sw"); + + if (flags & TCA_CLS_FLAGS_IN_HW) + fprintf(f, "\n in_hw"); + else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) + fprintf(f, "\n not_in_hw"); + } + + if (tb[TCA_MATCHALL_ACT]) + tc_print_action(f, tb[TCA_MATCHALL_ACT], 0); + + return 0; +} + +struct filter_util matchall_filter_util = { + .id = "matchall", + .parse_fopt = matchall_parse_opt, + .print_fopt = matchall_print_opt, +}; diff --git a/tc/f_route.c b/tc/f_route.c index 4e9032c5..e88313f6 100644 --- a/tc/f_route.c +++ b/tc/f_route.c @@ -36,14 +36,11 @@ static void explain(void) static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { - struct tc_police tp; struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __u32 fh = 0xFFFF8000; __u32 order = 0; - memset(&tp, 0, sizeof(tp)); - if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); @@ -60,6 +57,7 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char while (argc > 0) { if (matches(*argv, "to") == 0) { __u32 id; + NEXT_ARG(); if (rtnl_rtrealm_a2n(&id, *argv)) { fprintf(stderr, "Illegal \"to\"\n"); @@ -70,6 +68,7 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char fh |= id&0xFF; } else if (matches(*argv, "from") == 0) { __u32 id; + NEXT_ARG(); if (rtnl_rtrealm_a2n(&id, *argv)) { fprintf(stderr, "Illegal \"from\"\n"); @@ -80,9 +79,10 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char fh |= id<<16; } else if (matches(*argv, "fromif") == 0) { __u32 id; + NEXT_ARG(); ll_init_map(&rth); - if ((id=ll_name_to_index(*argv)) <= 0) { + if ((id = ll_name_to_index(*argv)) <= 0) { fprintf(stderr, "Illegal \"fromif\"\n"); return -1; } @@ -91,7 +91,8 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char fh |= (0x8000|id)<<16; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -141,6 +142,7 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char static int route_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle) { struct rtattr *tb[TCA_ROUTE4_MAX+1]; + SPRINT_BUF(b1); if (opt == NULL) @@ -162,11 +164,11 @@ static int route_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, if (tb[TCA_ROUTE4_FROM]) fprintf(f, "from %s ", rtnl_rtrealm_n2a(rta_getattr_u32(tb[TCA_ROUTE4_FROM]), b1, sizeof(b1))); if (tb[TCA_ROUTE4_IIF]) - fprintf(f, "fromif %s", ll_index_to_name(*(int*)RTA_DATA(tb[TCA_ROUTE4_IIF]))); + fprintf(f, "fromif %s", ll_index_to_name(rta_getattr_u32(tb[TCA_ROUTE4_IIF]))); if (tb[TCA_ROUTE4_POLICE]) tc_print_police(f, tb[TCA_ROUTE4_POLICE]); if (tb[TCA_ROUTE4_ACT]) - tc_print_action(f, tb[TCA_ROUTE4_ACT]); + tc_print_action(f, tb[TCA_ROUTE4_ACT], 0); return 0; } diff --git a/tc/f_rsvp.c b/tc/f_rsvp.c index 1fe9b15f..65caeb42 100644 --- a/tc/f_rsvp.c +++ b/tc/f_rsvp.c @@ -37,7 +37,7 @@ static void explain(void) fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); } -static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, +static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix *addr, struct tc_rsvp_pinfo *pinfo, int dir, int family) { int argc = *argc_p; @@ -76,6 +76,7 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, if (strcmp(*argv, "spi/ah") == 0 || strcmp(*argv, "gpi/ah") == 0) { __u32 gpi; + NEXT_ARG(); if (get_u32(&gpi, *argv, 0)) return -1; @@ -88,6 +89,7 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, } else if (strcmp(*argv, "spi/esp") == 0 || strcmp(*argv, "gpi/esp") == 0) { __u32 gpi; + NEXT_ARG(); if (get_u32(&gpi, *argv, 0)) return -1; @@ -99,6 +101,7 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, argc--; argv++; } else if (strcmp(*argv, "flowlabel") == 0) { __u32 flabel; + NEXT_ARG(); if (get_u32(&flabel, *argv, 0)) return -1; @@ -114,6 +117,7 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, int sz = 1; __u32 tmp; __u32 mask = 0xff; + if (strcmp(*argv, "u32") == 0) { sz = 4; mask = 0xffff; @@ -169,15 +173,11 @@ done: static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { int family = strcmp(qu->id, "rsvp") == 0 ? AF_INET : AF_INET6; - struct tc_rsvp_pinfo pinfo; - struct tc_police tp; + struct tc_rsvp_pinfo pinfo = {}; struct tcmsg *t = NLMSG_DATA(n); int pinfo_ok = 0; struct rtattr *tail; - memset(&pinfo, 0, sizeof(pinfo)); - memset(&tp, 0, sizeof(tp)); - if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); @@ -194,6 +194,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * while (argc > 0) { if (matches(*argv, "session") == 0) { inet_prefix addr; + NEXT_ARG(); if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 1, family)) { fprintf(stderr, "Illegal \"session\"\n"); @@ -206,6 +207,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * } else if (matches(*argv, "sender") == 0 || matches(*argv, "flowspec") == 0) { inet_prefix addr; + NEXT_ARG(); if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 0, family)) { fprintf(stderr, "Illegal \"sender\"\n"); @@ -217,6 +219,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * continue; } else if (matches("ipproto", *argv) == 0) { int num; + NEXT_ARG(); num = inet_proto_a2n(*argv); if (num < 0) { @@ -227,7 +230,8 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * pinfo_ok++; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -235,7 +239,8 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * } addattr_l(n, 4096, TCA_RSVP_CLASSID, &handle, 4); } else if (strcmp(*argv, "tunnelid") == 0) { - unsigned tid; + unsigned int tid; + NEXT_ARG(); if (get_unsigned(&tid, *argv, 0)) { fprintf(stderr, "Illegal \"tunnelid\"\n"); @@ -244,7 +249,8 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * pinfo.tunnelid = tid; pinfo_ok++; } else if (strcmp(*argv, "tunnel") == 0) { - unsigned tid; + unsigned int tid; + NEXT_ARG(); if (get_unsigned(&tid, *argv, 0)) { fprintf(stderr, "Illegal \"tunnel\"\n"); @@ -292,7 +298,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * return 0; } -static char * sprint_spi(struct tc_rsvp_gpi *pi, int dir, char *buf) +static char *sprint_spi(struct tc_rsvp_gpi *pi, int dir, char *buf) { if (pi->offset == 0) { if (dir && pi->mask == htonl(0xFFFF)) { @@ -351,6 +357,7 @@ static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, _ if (tb[TCA_RSVP_DST]) { char buf[128]; + fprintf(f, "session "); if (inet_ntop(family, RTA_DATA(tb[TCA_RSVP_DST]), buf, sizeof(buf)) == 0) fprintf(f, " [INVALID DADDR] "); @@ -377,6 +384,7 @@ static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, _ fprintf(f, "tunnelid %d ", pinfo->tunnelid); if (tb[TCA_RSVP_SRC]) { char buf[128]; + fprintf(f, "sender "); if (inet_ntop(family, RTA_DATA(tb[TCA_RSVP_SRC]), buf, sizeof(buf)) == 0) { fprintf(f, "[BAD]"); @@ -394,7 +402,7 @@ static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, _ } if (tb[TCA_RSVP_ACT]) { - tc_print_action(f, tb[TCA_RSVP_ACT]); + tc_print_action(f, tb[TCA_RSVP_ACT], 0); } if (tb[TCA_RSVP_POLICE]) tc_print_police(f, tb[TCA_RSVP_POLICE]); diff --git a/tc/f_tcindex.c b/tc/f_tcindex.c index b1847c89..dd1cb475 100644 --- a/tc/f_tcindex.c +++ b/tc/f_tcindex.c @@ -17,22 +17,20 @@ static void explain(void) { - fprintf(stderr," Usage: ... tcindex [ hash SIZE ] [ mask MASK ]" - " [ shift SHIFT ]\n"); - fprintf(stderr," [ pass_on | fall_through ]\n"); - fprintf(stderr," [ classid CLASSID ] " - "[ action ACTION_SPEC ]\n"); + fprintf(stderr," Usage: ... tcindex [ hash SIZE ] [ mask MASK ] [ shift SHIFT ]\n"); + fprintf(stderr, " [ pass_on | fall_through ]\n"); + fprintf(stderr," [ classid CLASSID ] [ action ACTION_SPEC ]\n"); } static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, - char **argv, struct nlmsghdr *n) + char **argv, struct nlmsghdr *n) { struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; char *end; if (handle) { - t->tcm_handle = strtoul(handle,&end,0); + t->tcm_handle = strtoul(handle, &end, 0); if (*end) { fprintf(stderr, "Illegal filter ID\n"); return -1; @@ -40,81 +38,75 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, } if (!argc) return 0; tail = NLMSG_TAIL(n); - addattr_l(n,4096,TCA_OPTIONS,NULL,0); + addattr_l(n, 4096, TCA_OPTIONS, NULL, 0); while (argc) { - if (!strcmp(*argv,"hash")) { + if (!strcmp(*argv, "hash")) { int hash; NEXT_ARG(); - hash = strtoul(*argv,&end,0); + hash = strtoul(*argv, &end, 0); if (*end || !hash || hash > 0x10000) { explain(); return -1; } - addattr_l(n,4096,TCA_TCINDEX_HASH,&hash,sizeof(hash)); - } - else if (!strcmp(*argv,"mask")) { + addattr_l(n, 4096, TCA_TCINDEX_HASH, &hash, + sizeof(hash)); + } else if (!strcmp(*argv,"mask")) { __u16 mask; NEXT_ARG(); - mask = strtoul(*argv,&end,0); + mask = strtoul(*argv, &end, 0); if (*end) { explain(); return -1; } - addattr_l(n,4096,TCA_TCINDEX_MASK,&mask,sizeof(mask)); - } - else if (!strcmp(*argv,"shift")) { + addattr_l(n, 4096, TCA_TCINDEX_MASK, &mask, + sizeof(mask)); + } else if (!strcmp(*argv,"shift")) { int shift; NEXT_ARG(); - shift = strtoul(*argv,&end,0); + shift = strtoul(*argv, &end, 0); if (*end) { explain(); return -1; } - addattr_l(n,4096,TCA_TCINDEX_SHIFT,&shift, + addattr_l(n, 4096, TCA_TCINDEX_SHIFT, &shift, sizeof(shift)); - } - else if (!strcmp(*argv,"fall_through")) { + } else if (!strcmp(*argv,"fall_through")) { int value = 1; - addattr_l(n,4096,TCA_TCINDEX_FALL_THROUGH,&value, + addattr_l(n, 4096, TCA_TCINDEX_FALL_THROUGH, &value, sizeof(value)); - } - else if (!strcmp(*argv,"pass_on")) { + } else if (!strcmp(*argv,"pass_on")) { int value = 0; - addattr_l(n,4096,TCA_TCINDEX_FALL_THROUGH,&value, + addattr_l(n, 4096, TCA_TCINDEX_FALL_THROUGH, &value, sizeof(value)); - } - else if (!strcmp(*argv,"classid")) { + } else if (!strcmp(*argv,"classid")) { __u32 handle; NEXT_ARG(); - if (get_tc_classid(&handle,*argv)) { + if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); return -1; } addattr_l(n, 4096, TCA_TCINDEX_CLASSID, &handle, 4); - } - else if (!strcmp(*argv,"police")) { + } else if (!strcmp(*argv,"police")) { NEXT_ARG(); if (parse_police(&argc, &argv, TCA_TCINDEX_POLICE, n)) { fprintf(stderr, "Illegal \"police\"\n"); return -1; } continue; - } - else if (!strcmp(*argv,"action")) { + } else if (!strcmp(*argv,"action")) { NEXT_ARG(); - if (parse_police(&argc, &argv, TCA_TCINDEX_ACT, n)) { + if (parse_action(&argc, &argv, TCA_TCINDEX_ACT, n)) { fprintf(stderr, "Illegal \"action\"\n"); return -1; } continue; - } - else { + } else { explain(); return -1; } @@ -127,7 +119,7 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, static int tcindex_print_opt(struct filter_util *qu, FILE *f, - struct rtattr *opt, __u32 handle) + struct rtattr *opt, __u32 handle) { struct rtattr *tb[TCA_TCINDEX_MAX+1]; @@ -136,14 +128,14 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, parse_rtattr_nested(tb, TCA_TCINDEX_MAX, opt); - if (handle != ~0) fprintf(f,"handle 0x%04x ",handle); + if (handle != ~0) fprintf(f, "handle 0x%04x ", handle); if (tb[TCA_TCINDEX_HASH]) { __u16 hash; if (RTA_PAYLOAD(tb[TCA_TCINDEX_HASH]) < sizeof(hash)) return -1; hash = rta_getattr_u16(tb[TCA_TCINDEX_HASH]); - fprintf(f,"hash %d ",hash); + fprintf(f, "hash %d ", hash); } if (tb[TCA_TCINDEX_MASK]) { __u16 mask; @@ -151,15 +143,15 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, if (RTA_PAYLOAD(tb[TCA_TCINDEX_MASK]) < sizeof(mask)) return -1; mask = rta_getattr_u16(tb[TCA_TCINDEX_MASK]); - fprintf(f,"mask 0x%04x ",mask); + fprintf(f, "mask 0x%04x ", mask); } if (tb[TCA_TCINDEX_SHIFT]) { int shift; if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT]) < sizeof(shift)) return -1; - shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT]); - fprintf(f,"shift %d ",shift); + shift = rta_getattr_u32(tb[TCA_TCINDEX_SHIFT]); + fprintf(f, "shift %d ", shift); } if (tb[TCA_TCINDEX_FALL_THROUGH]) { int fall_through; @@ -167,12 +159,12 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH]) < sizeof(fall_through)) return -1; - fall_through = *(int *) RTA_DATA(tb[TCA_TCINDEX_FALL_THROUGH]); - fprintf(f,fall_through ? "fall_through " : "pass_on "); + fall_through = rta_getattr_u32(tb[TCA_TCINDEX_FALL_THROUGH]); + fprintf(f, fall_through ? "fall_through " : "pass_on "); } if (tb[TCA_TCINDEX_CLASSID]) { SPRINT_BUF(b1); - fprintf(f, "classid %s ",sprint_tc_classid(*(__u32 *) + fprintf(f, "classid %s ", sprint_tc_classid(*(__u32 *) RTA_DATA(tb[TCA_TCINDEX_CLASSID]), b1)); } if (tb[TCA_TCINDEX_POLICE]) { @@ -181,7 +173,7 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, } if (tb[TCA_TCINDEX_ACT]) { fprintf(f, "\n"); - tc_print_police(f, tb[TCA_TCINDEX_ACT]); + tc_print_action(f, tb[TCA_TCINDEX_ACT], 0); } return 0; } @@ -30,24 +30,23 @@ extern int show_pretty; static void explain(void) { - fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ]" - " [ classid CLASSID ]\n"); - fprintf(stderr, " [ action ACTION_SPEC ]" - " [ offset OFFSET_SPEC ]\n"); - fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"); - fprintf(stderr, " [ sample SAMPLE ]\n"); - fprintf(stderr, "or u32 divisor DIVISOR\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); - fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp |" - " u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n"); - fprintf(stderr, " FILTERID := X:Y:Z\n"); - fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n"); + fprintf(stderr, + "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n" + " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n" + " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n" + " [ sample SAMPLE ] [skip_hw | skip_sw]\n" + "or u32 divisor DIVISOR\n" + "\n" + "Where: SELECTOR := SAMPLE SAMPLE ...\n" + " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n" + " SAMPLE_ARGS [ divisor DIVISOR ]\n" + " FILTERID := X:Y:Z\n" + "\nNOTE: CLASSID is parsed at hexadecimal input.\n"); } static int get_u32_handle(__u32 *handle, const char *str) { - __u32 htid=0, hash=0, nodeid=0; + __u32 htid = 0, hash = 0, nodeid = 0; char *tmp = strchr(str, ':'); if (tmp == NULL) { @@ -58,21 +57,21 @@ static int get_u32_handle(__u32 *handle, const char *str) htid = strtoul(str, &tmp, 16); if (tmp == str && *str != ':' && *str != 0) return -1; - if (htid>=0x1000) + if (htid >= 0x1000) return -1; if (*tmp) { str = tmp + 1; hash = strtoul(str, &tmp, 16); if (tmp == str && *str != ':' && *str != 0) return -1; - if (hash>=0x100) + if (hash >= 0x100) return -1; if (*tmp) { str = tmp + 1; nodeid = strtoul(str, &tmp, 16); if (tmp == str && *str != 0) return -1; - if (nodeid>=0x1000) + if (nodeid >= 0x1000) return -1; } } @@ -80,7 +79,7 @@ static int get_u32_handle(__u32 *handle, const char *str) return 0; } -static char * sprint_u32_handle(__u32 handle, char *buf) +static char *sprint_u32_handle(__u32 handle, char *buf) { int bsize = SPRINT_BSIZE-1; __u32 htid = TC_U32_HTID(handle); @@ -94,17 +93,20 @@ static char * sprint_u32_handle(__u32 handle, char *buf) } if (htid) { int l = snprintf(b, bsize, "%x:", htid>>20); + bsize -= l; b += l; } if (nodeid|hash) { if (hash) { int l = snprintf(b, bsize, "%x", hash); + bsize -= l; b += l; } if (nodeid) { int l = snprintf(b, bsize, ":%x", nodeid); + bsize -= l; b += l; } @@ -122,7 +124,7 @@ static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, key &= mask; - for (i=0; i<hwm; i++) { + for (i = 0; i < hwm; i++) { if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) { __u32 intersect = mask & sel->keys[i].mask; @@ -171,7 +173,8 @@ static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask, return pack_key(sel, key, mask, off, offmask); } -static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask) +static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, + int offmask) { if (key > 0xFF || mask > 0xFF) return -1; @@ -382,14 +385,14 @@ static int parse_ip6_addr(int *argc_p, char ***argv_p, plen = addr.bitlen; for (i = 0; i < plen; i += 32) { -// if (((i + 31) & ~0x1F) <= plen) { - if (i + 31 <= plen) { + if (i + 31 < plen) { res = pack_key(sel, addr.data[i / 32], 0xFFFFFFFF, off + 4 * (i / 32), offmask); if (res < 0) return -1; } else if (i < plen) { __u32 mask = htonl(0xFFFFFFFF << (32 - (plen - i))); + res = pack_key(sel, addr.data[i / 32], mask, off + 4 * (i / 32), offmask); if (res < 0) @@ -712,7 +715,7 @@ static int parse_selector(int *argc_p, char ***argv_p, } else if (matches(*argv, "ip") == 0) { NEXT_ARG(); res = parse_ip(&argc, &argv, sel); - } else if (matches(*argv, "ip6") == 0) { + } else if (matches(*argv, "ip6") == 0) { NEXT_ARG(); res = parse_ip6(&argc, &argv, sel); } else if (matches(*argv, "udp") == 0) { @@ -746,6 +749,7 @@ static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) while (argc > 0) { if (matches(*argv, "plus") == 0) { int off; + NEXT_ARG(); if (get_integer(&off, *argv, 0)) return -1; @@ -753,6 +757,7 @@ static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) sel->flags |= TC_U32_OFFSET; } else if (matches(*argv, "at") == 0) { int off; + NEXT_ARG(); if (get_integer(&off, *argv, 0)) return -1; @@ -763,14 +768,13 @@ static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) } sel->flags |= TC_U32_VAROFFSET; } else if (matches(*argv, "mask") == 0) { - __u16 mask; NEXT_ARG(); - if (get_u16(&mask, *argv, 16)) + if (get_be16(&sel->offmask, *argv, 16)) return -1; - sel->offmask = htons(mask); sel->flags |= TC_U32_VAROFFSET; } else if (matches(*argv, "shift") == 0) { int shift; + NEXT_ARG(); if (get_integer(&shift, *argv, 0)) return -1; @@ -796,13 +800,12 @@ static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) while (argc > 0) { if (matches(*argv, "mask") == 0) { - __u32 mask; NEXT_ARG(); - if (get_u32(&mask, *argv, 16)) + if (get_be32(&sel->hmask, *argv, 16)) return -1; - sel->hmask = htonl(mask); } else if (matches(*argv, "at") == 0) { int num; + NEXT_ARG(); if (get_integer(&num, *argv, 0)) return -1; @@ -828,22 +831,26 @@ static void print_ipv4(FILE *f, const struct tc_u32_key *key) case 0: switch (ntohl(key->mask)) { case 0x0f000000: - fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24); + fprintf(f, "\n match IP ihl %u", + ntohl(key->val) >> 24); return; case 0x00ff0000: - fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16); + fprintf(f, "\n match IP dsfield %#x", + ntohl(key->val) >> 16); return; } break; case 8: if (ntohl(key->mask) == 0x00ff0000) { - fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16); + fprintf(f, "\n match IP protocol %d", + ntohl(key->val) >> 16); return; } break; case 12: case 16: { int bits = mask2bits(key->mask); + if (bits >= 0) { fprintf(f, "\n %s %s/%d", key->off == 12 ? "match IP src" : "match IP dst", @@ -884,22 +891,26 @@ static void print_ipv6(FILE *f, const struct tc_u32_key *key) case 0: switch (ntohl(key->mask)) { case 0x0f000000: - fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24); + fprintf(f, "\n match IP ihl %u", + ntohl(key->val) >> 24); return; case 0x00ff0000: - fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16); + fprintf(f, "\n match IP dsfield %#x", + ntohl(key->val) >> 16); return; } break; case 8: if (ntohl(key->mask) == 0x00ff0000) { - fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16); + fprintf(f, "\n match IP protocol %d", + ntohl(key->val) >> 16); return; } break; case 12: case 16: { int bits = mask2bits(key->mask); + if (bits >= 0) { fprintf(f, "\n %s %s/%d", key->off == 12 ? "match IP src" : "match IP dst", @@ -946,7 +957,7 @@ static const struct { __u16 pad; void (*pprinter)(FILE *f, const struct tc_u32_key *key); } u32_pprinters[] = { - {0, 0, print_raw}, + {0, 0, print_raw}, {ETH_P_IP, 0, print_ipv4}, {ETH_P_IPV6, 0, print_ipv6}, }; @@ -958,7 +969,7 @@ static void show_keys(FILE *f, const struct tc_u32_key *key) if (!show_pretty) goto show_k; - for (i = 0; i < sizeof(u32_pprinters) / sizeof(u32_pprinters[0]); i++) { + for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) { if (u32_pprinters[i].proto == ntohs(f_proto)) { show_k: u32_pprinters[i].pprinter(f, key); @@ -976,15 +987,14 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, struct { struct tc_u32_sel sel; struct tc_u32_key keys[128]; - } sel; + } sel = {}; struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; int sel_ok = 0, terminal_ok = 0; int sample_ok = 0; __u32 htid = 0; __u32 order = 0; - - memset(&sel, 0, sizeof(sel)); + __u32 flags = 0; if (handle && get_u32_handle(&t->tcm_handle, handle)) { fprintf(stderr, "Illegal filter ID\n"); @@ -1022,16 +1032,18 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, continue; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned handle; + unsigned int flowid; + NEXT_ARG(); - if (get_tc_classid(&handle, *argv)) { + if (get_tc_classid(&flowid, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); return -1; } - addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4); + addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4); sel.sel.flags |= TC_U32_TERMINAL; } else if (matches(*argv, "divisor") == 0) { - unsigned divisor; + unsigned int divisor; + NEXT_ARG(); if (get_unsigned(&divisor, *argv, 0) || divisor == 0 || @@ -1047,55 +1059,56 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, return -1; } } else if (strcmp(*argv, "link") == 0) { - unsigned handle; + unsigned int linkid; + NEXT_ARG(); - if (get_u32_handle(&handle, *argv)) { + if (get_u32_handle(&linkid, *argv)) { fprintf(stderr, "Illegal \"link\"\n"); return -1; } - if (handle && TC_U32_NODE(handle)) { + if (linkid && TC_U32_NODE(linkid)) { fprintf(stderr, "\"link\" must be a hash table.\n"); return -1; } - addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4); + addattr_l(n, MAX_MSG, TCA_U32_LINK, &linkid, 4); } else if (strcmp(*argv, "ht") == 0) { - unsigned handle; + unsigned int ht; + NEXT_ARG(); - if (get_u32_handle(&handle, *argv)) { + if (get_u32_handle(&ht, *argv)) { fprintf(stderr, "Illegal \"ht\"\n"); return -1; } - if (handle && TC_U32_NODE(handle)) { + if (handle && TC_U32_NODE(ht)) { fprintf(stderr, "\"ht\" must be a hash table.\n"); return -1; } if (sample_ok) - htid = (htid & 0xFF000) | (handle & 0xFFF00000); + htid = (htid & 0xFF000) | (ht & 0xFFF00000); else - htid = (handle & 0xFFFFF000); + htid = (ht & 0xFFFFF000); } else if (strcmp(*argv, "sample") == 0) { __u32 hash; - unsigned divisor = 0x100; - + unsigned int divisor = 0x100; struct { struct tc_u32_sel sel; struct tc_u32_key keys[4]; - } sel2; - memset(&sel2, 0, sizeof(sel2)); + } sel2 = {}; + NEXT_ARG(); if (parse_selector(&argc, &argv, &sel2.sel, n)) { fprintf(stderr, "Illegal \"sample\"\n"); return -1; } if (sel2.sel.nkeys != 1) { - fprintf(stderr, "\"sample\" must contain" - " exactly ONE key.\n"); + fprintf(stderr, "\"sample\" must contain exactly ONE key.\n"); return -1; } if (*argv != 0 && strcmp(*argv, "divisor") == 0) { NEXT_ARG(); - if (get_unsigned(&divisor, *argv, 0) || divisor == 0 || - divisor > 0x100 || ((divisor - 1) & divisor)) { + if (get_unsigned(&divisor, *argv, 0) || + divisor == 0 || divisor > 0x100 || + ((divisor - 1) & divisor)) { fprintf(stderr, "Illegal sample \"divisor\"\n"); return -1; } @@ -1108,16 +1121,17 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, sample_ok = 1; continue; } else if (strcmp(*argv, "indev") == 0) { - char ind[IFNAMSIZ + 1]; - memset(ind, 0, sizeof (ind)); + char ind[IFNAMSIZ + 1] = {}; + 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); + 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(); @@ -1136,6 +1150,14 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, } terminal_ok++; continue; + } else if (strcmp(*argv, "skip_hw") == 0) { + NEXT_ARG(); + flags |= TCA_CLS_FLAGS_SKIP_HW; + continue; + } else if (strcmp(*argv, "skip_sw") == 0) { + NEXT_ARG(); + flags |= TCA_CLS_FLAGS_SKIP_SW; + continue; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; @@ -1152,7 +1174,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, sel.sel.flags |= TC_U32_TERMINAL; if (order) { - if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) { + if (TC_U32_NODE(t->tcm_handle) && + order != TC_U32_NODE(t->tcm_handle)) { fprintf(stderr, "\"order\" contradicts \"handle\"\n"); return -1; } @@ -1163,7 +1186,18 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4); if (sel_ok) addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, - sizeof(sel.sel) + sel.sel.nkeys * sizeof(struct tc_u32_key)); + sizeof(sel.sel) + + sel.sel.nkeys * sizeof(struct tc_u32_key)); + if (flags) { + if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | + TCA_CLS_FLAGS_SKIP_SW))) { + fprintf(stderr, + "skip_hw and skip_sw are mutually exclusive\n"); + return -1; + } + addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4); + } + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -1184,9 +1218,9 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, SPRINT_BUF(b1); fprintf(f, "fh %s ", sprint_u32_handle(handle, b1)); } - if (TC_U32_NODE(handle)) { + + if (TC_U32_NODE(handle)) fprintf(f, "order %d ", TC_U32_NODE(handle)); - } if (tb[TCA_U32_SEL]) { if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel)) @@ -1196,9 +1230,11 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, } if (tb[TCA_U32_DIVISOR]) { - fprintf(f, "ht divisor %d ", rta_getattr_u32(tb[TCA_U32_DIVISOR])); + fprintf(f, "ht divisor %d ", + rta_getattr_u32(tb[TCA_U32_DIVISOR])); } else if (tb[TCA_U32_HASH]) { __u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]); + fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid), TC_U32_HASH(htid)); } else { @@ -1208,19 +1244,35 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, SPRINT_BUF(b1); fprintf(f, "%sflowid %s ", !sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "", - sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]), b1)); + sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]), + b1)); } else if (sel && sel->flags & TC_U32_TERMINAL) { fprintf(f, "terminal flowid ??? "); } if (tb[TCA_U32_LINK]) { SPRINT_BUF(b1); fprintf(f, "link %s ", - sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]), b1)); + sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]), + b1)); + } + + if (tb[TCA_U32_FLAGS]) { + __u32 flags = rta_getattr_u32(tb[TCA_U32_FLAGS]); + + if (flags & TCA_CLS_FLAGS_SKIP_HW) + fprintf(f, "skip_hw "); + if (flags & TCA_CLS_FLAGS_SKIP_SW) + fprintf(f, "skip_sw "); + + if (flags & TCA_CLS_FLAGS_IN_HW) + fprintf(f, "in_hw "); + else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) + fprintf(f, "not_in_hw "); } if (tb[TCA_U32_PCNT]) { if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) { - fprintf(f, "Broken perf counters \n"); + fprintf(f, "Broken perf counters\n"); return -1; } pf = RTA_DATA(tb[TCA_U32_PCNT]); @@ -1233,6 +1285,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, if (tb[TCA_U32_MARK]) { struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]); + if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) { fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n"); } else { @@ -1244,7 +1297,8 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, if (sel) { if (sel->nkeys) { int i; - for (i=0; i<sel->nkeys; i++) { + + for (i = 0; i < sel->nkeys; i++) { show_keys(f, sel->keys + i); if (show_stats && NULL != pf) fprintf(f, " (success %llu ) ", @@ -1274,13 +1328,15 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, 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", rta_getattr_str(idev)); } - if (tb[TCA_U32_ACT]) { - tc_print_action(f, tb[TCA_U32_ACT]); - } + + if (tb[TCA_U32_ACT]) + tc_print_action(f, tb[TCA_U32_ACT], 0); return 0; } diff --git a/tc/m_action.c b/tc/m_action.c index 8d3d51e9..e8c94e57 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -28,16 +28,15 @@ #include "tc_common.h" #include "tc_util.h" -static struct action_util * action_list; - +static struct action_util *action_list; #ifdef ANDROID extern struct action_util mirred_action_util; #endif #ifdef CONFIG_GACT -int gact_ld = 0 ; //fuckin backward compatibility +int gact_ld; /* f*ckin backward compatibility */ #endif -int tab_flush = 0; +int tab_flush; static void act_usage(void) { @@ -48,10 +47,10 @@ static void act_usage(void) * does that, they would know how to fix this .. * */ - fprintf (stderr, "usage: tc actions <ACTSPECOP>*\n"); + fprintf(stderr, "usage: tc actions <ACTSPECOP>*\n"); fprintf(stderr, "Where: \tACTSPECOP := ACR | GD | FL\n" - "\tACR := add | change | replace <ACTSPEC>* \n" + "\tACR := add | change | replace <ACTSPEC>*\n" "\tGD := get | delete | <ACTISPEC>*\n" "\tFL := ls | list | flush | <ACTNAMESPEC>\n" "\tACTNAMESPEC := action <ACTNAME>\n" @@ -70,7 +69,7 @@ static int print_noaopt(struct action_util *au, FILE *f, struct rtattr *opt) { if (opt && RTA_PAYLOAD(opt)) fprintf(f, "[Unknown action, optlen=%u] ", - (unsigned) RTA_PAYLOAD(opt)); + (unsigned int) RTA_PAYLOAD(opt)); return 0; } @@ -135,13 +134,12 @@ noexist: #ifdef CONFIG_GACT if (!looked4gact) { looked4gact = 1; - strcpy(str,"gact"); + strcpy(str, "gact"); goto restart_s; } #endif - a = malloc(sizeof(*a)); + a = calloc(1, sizeof(*a)); if (a) { - memset(a, 0, sizeof(*a)); strncpy(a->id, "noact", 15); a->parse_aopt = parse_noaopt; a->print_aopt = print_noaopt; @@ -154,9 +152,9 @@ static int new_cmd(char **argv) { if ((matches(*argv, "change") == 0) || - (matches(*argv, "replace") == 0)|| - (matches(*argv, "delete") == 0)|| - (matches(*argv, "get") == 0)|| + (matches(*argv, "replace") == 0) || + (matches(*argv, "delete") == 0) || + (matches(*argv, "get") == 0) || (matches(*argv, "add") == 0)) return 1; @@ -164,18 +162,19 @@ new_cmd(char **argv) } -int -parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) +int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; struct rtattr *tail, *tail2; char k[16]; + int act_ck_len = 0; int ok = 0; int eap = 0; /* expect action parameters */ int ret = 0; int prio = 0; + unsigned char act_ck[TC_COOKIE_MAX_SIZE]; if (argc <= 0) return -1; @@ -186,9 +185,9 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) while (argc > 0) { - memset(k, 0, sizeof (k)); + memset(k, 0, sizeof(k)); - if (strcmp(*argv, "action") == 0 ) { + if (strcmp(*argv, "action") == 0) { argc--; argv++; eap = 1; @@ -208,9 +207,10 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) goto done0; } else { struct action_util *a = NULL; - strncpy(k, *argv, sizeof (k) - 1); + + strncpy(k, *argv, sizeof(k) - 1); eap = 0; - if (argc > 0 ) { + if (argc > 0) { a = get_action_kind(k); } else { done0: @@ -220,7 +220,7 @@ done0: goto done; } - if (NULL == a) { + if (a == NULL) { goto bad_val; } @@ -228,20 +228,48 @@ done0: addattr_l(n, MAX_MSG, ++prio, NULL, 0); addattr_l(n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1); - ret = a->parse_aopt(a,&argc, &argv, TCA_ACT_OPTIONS, n); + ret = a->parse_aopt(a, &argc, &argv, TCA_ACT_OPTIONS, + n); if (ret < 0) { - fprintf(stderr,"bad action parsing\n"); + fprintf(stderr, "bad action parsing\n"); goto bad_val; } + + if (*argv && strcmp(*argv, "cookie") == 0) { + size_t slen; + + NEXT_ARG(); + slen = strlen(*argv); + if (slen > TC_COOKIE_MAX_SIZE * 2) { + char cookie_err_m[128]; + + snprintf(cookie_err_m, 128, + "%zd Max allowed size %d", + slen, TC_COOKIE_MAX_SIZE*2); + invarg(cookie_err_m, *argv); + } + + if (hex2mem(*argv, act_ck, slen / 2) < 0) + invarg("cookie must be a hex string\n", + *argv); + + act_ck_len = slen / 2; + argc--; + argv++; + } + + if (act_ck_len) + addattr_l(n, MAX_MSG, TCA_ACT_COOKIE, + &act_ck, act_ck_len); + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; ok++; } - } if (eap > 0) { - fprintf(stderr,"bad action empty %d\n",eap); + fprintf(stderr, "bad action empty %d\n", eap); goto bad_val; } @@ -254,12 +282,11 @@ done: bad_val: /* no need to undo things, returning from here should * cause enough pain */ - fprintf(stderr, "parse_action: bad value (%d:%s)!\n",argc,*argv); + fprintf(stderr, "parse_action: bad value (%d:%s)!\n", argc, *argv); return -1; } -static int -tc_print_one_action(FILE * f, struct rtattr *arg) +static int tc_print_one_action(FILE *f, struct rtattr *arg) { struct rtattr *tb[TCA_ACT_MAX + 1]; @@ -278,17 +305,26 @@ tc_print_one_action(FILE * f, struct rtattr *arg) a = get_action_kind(RTA_DATA(tb[TCA_ACT_KIND])); - if (NULL == a) + if (a == NULL) return err; err = a->print_aopt(a, f, tb[TCA_ACT_OPTIONS]); - if (0 > err) + if (err < 0) return err; if (show_stats && tb[TCA_ACT_STATS]) { + fprintf(f, "\tAction statistics:\n"); print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL); + if (tb[TCA_ACT_COOKIE]) { + int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]); + char b1[strsz * 2 + 1]; + + fprintf(f, "\n\tcookie len %d %s ", strsz, + hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]), + strsz, b1, sizeof(b1))); + } fprintf(f, "\n"); } @@ -312,34 +348,38 @@ tc_print_action_flush(FILE *f, const struct rtattr *arg) } a = get_action_kind(RTA_DATA(tb[TCA_KIND])); - if (NULL == a) + if (a == NULL) return err; delete_count = RTA_DATA(tb[TCA_FCNT]); - fprintf(f," %s (%d entries)\n", a->id, *delete_count); + fprintf(f, " %s (%d entries)\n", a->id, *delete_count); tab_flush = 0; return 0; } int -tc_print_action(FILE *f, const struct rtattr *arg) +tc_print_action(FILE *f, const struct rtattr *arg, unsigned short tot_acts) { int i; - struct rtattr *tb[TCA_ACT_MAX_PRIO + 1]; if (arg == NULL) return 0; - parse_rtattr_nested(tb, TCA_ACT_MAX_PRIO, arg); + if (!tot_acts) + tot_acts = TCA_ACT_MAX_PRIO; + + struct rtattr *tb[tot_acts + 1]; + + parse_rtattr_nested(tb, tot_acts, arg); if (tab_flush && NULL != tb[0] && NULL == tb[1]) return tc_print_action_flush(f, tb[0]); - for (i = 0; i < TCA_ACT_MAX_PRIO; i++) { + for (i = 0; i < tot_acts; i++) { if (tb[i]) { fprintf(f, "\n\taction order %d: ", i); - if (0 > tc_print_one_action(f, tb[i])) { + if (tc_print_one_action(f, tb[i]) < 0) { fprintf(f, "Error printing action\n"); } } @@ -353,10 +393,11 @@ int print_action(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct tcamsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[TCAA_MAX+1]; + __u32 *tot_acts = NULL; + struct rtattr *tb[TCA_ROOT_MAX+1]; len -= NLMSG_LENGTH(sizeof(*t)); @@ -365,9 +406,13 @@ int print_action(const struct sockaddr_nl *who, return -1; } - parse_rtattr(tb, TCAA_MAX, TA_RTA(t), len); + parse_rtattr(tb, TCA_ROOT_MAX, TA_RTA(t), len); + + if (tb[TCA_ROOT_COUNT]) + tot_acts = RTA_DATA(tb[TCA_ROOT_COUNT]); - if (NULL == tb[TCA_ACT_TAB]) { + fprintf(fp, "total acts %d\n", tot_acts ? *tot_acts:0); + if (tb[TCA_ACT_TAB] == NULL) { if (n->nlmsg_type != RTM_GETACTION) fprintf(stderr, "print_action: NULL kind\n"); return -1; @@ -378,18 +423,26 @@ int print_action(const struct sockaddr_nl *who, fprintf(fp, "Flushed table "); tab_flush = 1; } else { - fprintf(fp, "deleted action "); + fprintf(fp, "Deleted action "); } } - if (n->nlmsg_type == RTM_NEWACTION) - fprintf(fp, "Added action "); - tc_print_action(fp, tb[TCA_ACT_TAB]); + if (n->nlmsg_type == RTM_NEWACTION) { + if ((n->nlmsg_flags & NLM_F_CREATE) && + !(n->nlmsg_flags & NLM_F_REPLACE)) { + fprintf(fp, "Added action "); + } else if (n->nlmsg_flags & NLM_F_REPLACE) { + fprintf(fp, "Replaced action "); + } + } + + + tc_print_action(fp, tb[TCA_ACT_TAB], tot_acts ? *tot_acts:0); return 0; } -static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) +static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p) { char k[16]; struct action_util *a = NULL; @@ -397,8 +450,7 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) char **argv = *argv_p; int prio = 0; int ret = 0; - __u32 i; - struct sockaddr_nl nladdr; + __u32 i = 0; struct rtattr *tail; struct rtattr *tail2; struct nlmsghdr *ans = NULL; @@ -407,27 +459,22 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; - } req; - - req.t.tca_family = AF_UNSPEC; - - memset(&req, 0, sizeof(req)); - - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .t.tca_family = AF_UNSPEC, + }; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - argc -=1; - argv +=1; + argc -= 1; + argv += 1; tail = NLMSG_TAIL(&req.n); addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0); while (argc > 0) { - if (strcmp(*argv, "action") == 0 ) { + if (strcmp(*argv, "action") == 0) { argc--; argv++; continue; @@ -435,23 +482,23 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) return -1; } - strncpy(k, *argv, sizeof (k) - 1); + strncpy(k, *argv, sizeof(k) - 1); a = get_action_kind(k); - if (NULL == a) { - fprintf(stderr, "Error: non existent action: %s\n",k); + if (a == NULL) { + fprintf(stderr, "Error: non existent action: %s\n", k); ret = -1; goto bad_val; } if (strcmp(a->id, k) != 0) { - fprintf(stderr, "Error: non existent action: %s\n",k); + fprintf(stderr, "Error: non existent action: %s\n", k); ret = -1; goto bad_val; } - argc -=1; - argv +=1; + argc -= 1; + argv += 1; if (argc <= 0) { - fprintf(stderr, "Error: no index specified action: %s\n",k); + fprintf(stderr, "Error: no index specified action: %s\n", k); ret = -1; goto bad_val; } @@ -463,10 +510,10 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) ret = -1; goto bad_val; } - argc -=1; - argv +=1; + argc -= 1; + argv += 1; } else { - fprintf(stderr, "Error: no index specified action: %s\n",k); + fprintf(stderr, "Error: no index specified action: %s\n", k); ret = -1; goto bad_val; } @@ -474,7 +521,8 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) tail2 = NLMSG_TAIL(&req.n); addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0); addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1); - addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i); + if (i > 0) + addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i); tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2; } @@ -490,7 +538,7 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) return 1; } - if (ans && 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; } @@ -501,29 +549,25 @@ bad_val: return ret; } -static int tc_action_modify(int cmd, unsigned flags, int *argc_p, char ***argv_p) +static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***argv_p) { int argc = *argc_p; char **argv = *argv_p; int ret = 0; - - struct rtattr *tail; struct { struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; - } req; - - req.t.tca_family = AF_UNSPEC; - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - tail = NLMSG_TAIL(&req.n); - argc -=1; - argv +=1; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .t.tca_family = AF_UNSPEC, + }; + struct rtattr *tail = NLMSG_TAIL(&req.n); + + argc -= 1; + argv += 1; if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) { fprintf(stderr, "Illegal \"action\"\n"); return -1; @@ -541,50 +585,71 @@ static int tc_action_modify(int cmd, unsigned flags, int *argc_p, char ***argv_p return ret; } -static int tc_act_list_or_flush(int argc, char **argv, int event) +static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event) { + struct rtattr *tail, *tail2, *tail3, *tail4; int ret = 0, prio = 0, msg_size = 0; - char k[16]; - struct rtattr *tail,*tail2; struct action_util *a = NULL; + struct nla_bitfield32 flag_select = { 0 }; + char **argv = *argv_p; + __u32 msec_since = 0; + int argc = *argc_p; + char k[16]; struct { struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; - } req; - - req.t.tca_family = AF_UNSPEC; - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .t.tca_family = AF_UNSPEC, + }; tail = NLMSG_TAIL(&req.n); addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0); tail2 = NLMSG_TAIL(&req.n); - strncpy(k, *argv, sizeof (k) - 1); + strncpy(k, *argv, sizeof(k) - 1); #ifdef CONFIG_GACT if (!gact_ld) { get_action_kind("gact"); } #endif a = get_action_kind(k); - if (NULL == a) { - fprintf(stderr,"bad action %s\n",k); + if (a == NULL) { + fprintf(stderr, "bad action %s\n", k); goto bad_val; } if (strcmp(a->id, k) != 0) { - fprintf(stderr,"bad action %s\n",k); + fprintf(stderr, "bad action %s\n", k); goto bad_val; } - strncpy(k, *argv, sizeof (k) - 1); + strncpy(k, *argv, sizeof(k) - 1); + + argc -= 1; + argv += 1; + + if (argc && (strcmp(*argv, "since") == 0)) { + NEXT_ARG(); + if (get_u32(&msec_since, *argv, 0)) + invarg("dump time \"since\" is invalid", *argv); + } addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0); addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1); tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2; tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail; + tail3 = NLMSG_TAIL(&req.n); + flag_select.value |= TCA_FLAG_LARGE_DUMP_ON; + flag_select.selector |= TCA_FLAG_LARGE_DUMP_ON; + addattr_l(&req.n, MAX_MSG, TCA_ROOT_FLAGS, &flag_select, + sizeof(struct nla_bitfield32)); + tail3->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail3; + if (msec_since) { + tail4 = NLMSG_TAIL(&req.n); + addattr32(&req.n, MAX_MSG, TCA_ROOT_TIME_DELTA, msec_since); + tail4->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail4; + } msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr)); if (event == RTM_GETACTION) { @@ -609,6 +674,8 @@ static int tc_act_list_or_flush(int argc, char **argv, int event) bad_val: + *argc_p = argc; + *argv_p = argv; return ret; } @@ -625,12 +692,12 @@ int do_action(int argc, char **argv) matches(*argv, "replace") == 0) { ret = tc_action_modify(RTM_NEWACTION, NLM_F_CREATE|NLM_F_REPLACE, &argc, &argv); } else if (matches(*argv, "delete") == 0) { - argc -=1; - argv +=1; + argc -= 1; + argv += 1; ret = tc_action_gd(RTM_DELACTION, 0, &argc, &argv); } else if (matches(*argv, "get") == 0) { - argc -=1; - argv +=1; + argc -= 1; + argv += 1; ret = tc_action_gd(RTM_GETACTION, 0, &argc, &argv); } else if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 || matches(*argv, "lst") == 0) { @@ -638,25 +705,31 @@ int do_action(int argc, char **argv) act_usage(); return -1; } - return tc_act_list_or_flush(argc-2, argv+2, RTM_GETACTION); + + argc -= 2; + argv += 2; + return tc_act_list_or_flush(&argc, &argv, + RTM_GETACTION); } else if (matches(*argv, "flush") == 0) { if (argc <= 2) { act_usage(); return -1; } - return tc_act_list_or_flush(argc-2, argv+2, RTM_DELACTION); + + argc -= 2; + argv += 2; + return tc_act_list_or_flush(&argc, &argv, + RTM_DELACTION); } else if (matches(*argv, "help") == 0) { act_usage(); return -1; } else { - - ret = -1; - } - - if (ret < 0) { fprintf(stderr, "Command \"%s\" is unknown, try \"tc actions help\".\n", *argv); return -1; } + + if (ret < 0) + return -1; } return 0; @@ -17,18 +17,12 @@ #include <linux/tc_act/tc_bpf.h> #include "utils.h" + #include "tc_util.h" -#include "tc_bpf.h" +#include "bpf_util.h" static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_ACT; -static const int nla_tbl[BPF_NLA_MAX] = { - [BPF_NLA_OPS_LEN] = TCA_ACT_BPF_OPS_LEN, - [BPF_NLA_OPS] = TCA_ACT_BPF_OPS, - [BPF_NLA_FD] = TCA_ACT_BPF_FD, - [BPF_NLA_NAME] = TCA_ACT_BPF_NAME, -}; - static void explain(void) { fprintf(stderr, "Usage: ... bpf ... [ index INDEX ]\n"); @@ -50,7 +44,7 @@ static void explain(void) fprintf(stderr, "pinned eBPF program.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where ACT_NAME refers to the section name containing the\n"); - fprintf(stderr, "action (default \'%s\').\n", bpf_default_section(bpf_type)); + fprintf(stderr, "action (default \'%s\').\n", bpf_prog_to_default_section(bpf_type)); fprintf(stderr, "\n"); fprintf(stderr, "Where UDS_FILE points to a unix domain socket file in order\n"); fprintf(stderr, "to hand off control of all created eBPF maps to an agent.\n"); @@ -59,11 +53,30 @@ static void explain(void) fprintf(stderr, "explicitly specifies an action index upon creation.\n"); } +static void bpf_cbpf_cb(void *nl, const struct sock_filter *ops, int ops_len) +{ + addattr16(nl, MAX_MSG, TCA_ACT_BPF_OPS_LEN, ops_len); + addattr_l(nl, MAX_MSG, TCA_ACT_BPF_OPS, ops, + ops_len * sizeof(struct sock_filter)); +} + +static void bpf_ebpf_cb(void *nl, int fd, const char *annotation) +{ + addattr32(nl, MAX_MSG, TCA_ACT_BPF_FD, fd); + addattrstrz(nl, MAX_MSG, TCA_ACT_BPF_NAME, annotation); +} + +static const struct bpf_cfg_ops bpf_cb_ops = { + .cbpf_cb = bpf_cbpf_cb, + .ebpf_cb = bpf_ebpf_cb, +}; + static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, int tca_id, struct nlmsghdr *n) { const char *bpf_obj = NULL, *bpf_uds_name = NULL; - struct tc_act_bpf parm; + struct tc_act_bpf parm = {}; + struct bpf_cfg_in cfg = {}; bool seen_run = false; struct rtattr *tail; int argc, ret = 0; @@ -85,11 +98,17 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, NEXT_ARG(); opt_bpf: seen_run = true; - if (bpf_parse_common(&argc, &argv, nla_tbl, bpf_type, - &bpf_obj, &bpf_uds_name, n)) { - fprintf(stderr, "Failed to retrieve (e)BPF data!\n"); + cfg.argc = argc; + cfg.argv = argv; + + if (bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, n)) return -1; - } + + argc = cfg.argc; + argv = cfg.argv; + + bpf_obj = cfg.object; + bpf_uds_name = cfg.uds; } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -104,29 +123,8 @@ opt_bpf: NEXT_ARG_FWD(); } - memset(&parm, 0, sizeof(parm)); - parm.action = TC_ACT_PIPE; - - if (argc) { - if (matches(*argv, "reclassify") == 0) { - parm.action = TC_ACT_RECLASSIFY; - NEXT_ARG_FWD(); - } else if (matches(*argv, "pipe") == 0) { - parm.action = TC_ACT_PIPE; - NEXT_ARG_FWD(); - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - parm.action = TC_ACT_SHOT; - NEXT_ARG_FWD(); - } else if (matches(*argv, "continue") == 0) { - parm.action = TC_ACT_UNSPEC; - NEXT_ARG_FWD(); - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - parm.action = TC_ACT_OK; - NEXT_ARG_FWD(); - } - } + parse_action_control_dflt(&argc, &argv, &parm.action, + false, TC_ACT_PIPE); if (argc) { if (matches(*argv, "index") == 0) { @@ -156,7 +154,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) { struct rtattr *tb[TCA_ACT_BPF_MAX + 1]; struct tc_act_bpf *parm; - SPRINT_BUF(action_buf); + int dump_ok = 0; if (arg == NULL) return -1; @@ -173,8 +171,6 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) if (tb[TCA_ACT_BPF_NAME]) fprintf(f, "%s ", rta_getattr_str(tb[TCA_ACT_BPF_NAME])); - else if (tb[TCA_ACT_BPF_FD]) - fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_ACT_BPF_FD])); if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) { bpf_print_ops(f, tb[TCA_ACT_BPF_OPS], @@ -182,14 +178,25 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) fprintf(f, " "); } - fprintf(f, "default-action %s\n", action_n2a(parm->action, action_buf, - sizeof(action_buf))); - fprintf(f, "\tindex %d ref %d bind %d", parm->index, parm->refcnt, + if (tb[TCA_ACT_BPF_ID]) + dump_ok = bpf_dump_prog_info(f, rta_getattr_u32(tb[TCA_ACT_BPF_ID])); + if (!dump_ok && tb[TCA_ACT_BPF_TAG]) { + SPRINT_BUF(b); + + fprintf(f, "tag %s ", + hexstring_n2a(RTA_DATA(tb[TCA_ACT_BPF_TAG]), + RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]), + b, sizeof(b))); + } + + print_action_control(f, "default-action ", parm->action, "\n"); + fprintf(f, "\tindex %u ref %d bind %d", parm->index, parm->refcnt, parm->bindcnt); if (show_stats) { if (tb[TCA_ACT_BPF_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]); + print_tm(f, tm); } } diff --git a/tc/m_connmark.c b/tc/m_connmark.c index 6974c9ba..37d71854 100644 --- a/tc/m_connmark.c +++ b/tc/m_connmark.c @@ -27,10 +27,11 @@ static void explain(void) { - fprintf(stderr, "Usage: ... connmark [zone ZONE] [BRANCH] [index <INDEX>]\n"); + fprintf(stderr, "Usage: ... connmark [zone ZONE] [CONTROL] [index <INDEX>]\n"); fprintf(stderr, "where :\n" "\tZONE is the conntrack zone\n" - "\tBRANCH := reclassify|pipe|drop|continue|ok\n"); + "\tCONTROL := reclassify | pipe | drop | continue | ok |\n" + "\t goto chain <CHAIN_INDEX>\n"); } static void @@ -80,31 +81,7 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, } } - sel.action = TC_ACT_PIPE; - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0) { - sel.action = TC_ACT_OK; - argc--; - argv++; - } - } + parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_PIPE); if (argc) { if (matches(*argv, "index") == 0) { @@ -145,12 +122,13 @@ static int print_connmark(struct action_util *au, FILE *f, struct rtattr *arg) ci = RTA_DATA(tb[TCA_CONNMARK_PARMS]); fprintf(f, " connmark zone %d\n", ci->zone); - fprintf(f, "\t index %d ref %d bind %d", ci->index, + fprintf(f, "\t index %u ref %d bind %d", ci->index, ci->refcnt, ci->bindcnt); if (show_stats) { if (tb[TCA_CONNMARK_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_CONNMARK_TM]); + print_tm(f, tm); } } diff --git a/tc/m_csum.c b/tc/m_csum.c index f7da6f0a..7b156734 100644 --- a/tc/m_csum.c +++ b/tc/m_csum.c @@ -24,8 +24,7 @@ explain(void) { fprintf(stderr, "Usage: ... csum <UPDATE>\n" "Where: UPDATE := <TARGET> [<UPDATE>]\n" - " TARGET := { ip4h | icmp | igmp |" - " tcp | udp | udplite | <SWEETS> }\n" + " TARGET := { ip4h | icmp | igmp | tcp | udp | udplite | sctp | <SWEETS> }\n" " SWEETS := { and | or | \'+\' }\n"); } @@ -45,7 +44,7 @@ parse_csum_args(int *argc_p, char ***argv_p, struct tc_csum *sel) if (argc <= 0) return -1; - while(argc > 0) { + while (argc > 0) { if ((matches(*argv, "iph") == 0) || (matches(*argv, "ip4h") == 0) || (matches(*argv, "ipv4h") == 0)) @@ -66,6 +65,9 @@ parse_csum_args(int *argc_p, char ***argv_p, struct tc_csum *sel) else if (matches(*argv, "udplite") == 0) sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDPLITE; + else if (matches(*argv, "sctp") == 0) + sel->update_flags |= TCA_CSUM_UPDATE_FLAG_SCTP; + else if ((matches(*argv, "and") == 0) || (matches(*argv, "or") == 0) || (matches(*argv, "+") == 0)) @@ -86,15 +88,13 @@ static int parse_csum(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { - struct tc_csum sel; + struct tc_csum sel = {}; int argc = *argc_p; char **argv = *argv_p; int ok = 0; struct rtattr *tail; - memset(&sel, 0, sizeof(sel)); - while (argc > 0) { if (matches(*argv, "csum") == 0) { NEXT_ARG(); @@ -108,8 +108,7 @@ parse_csum(struct action_util *a, int *argc_p, continue; } else if (matches(*argv, "help") == 0) { usage(); - } - else { + } else { break; } } @@ -124,30 +123,7 @@ parse_csum(struct action_util *a, int *argc_p, return -1; } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0) { - sel.action = TC_ACT_OK; - argc--; - argv++; - } - } + parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK); if (argc) { if (matches(*argv, "index") == 0) { @@ -174,7 +150,7 @@ parse_csum(struct action_util *a, int *argc_p, } static int -print_csum(struct action_util *au, FILE * f, struct rtattr *arg) +print_csum(struct action_util *au, FILE *f, struct rtattr *arg) { struct tc_csum *sel; @@ -186,7 +162,7 @@ print_csum(struct action_util *au, FILE * f, struct rtattr *arg) char *uflag_4 = ""; char *uflag_5 = ""; char *uflag_6 = ""; - SPRINT_BUF(action_buf); + char *uflag_7 = ""; int uflag_count = 0; @@ -212,26 +188,29 @@ print_csum(struct action_util *au, FILE * f, struct rtattr *arg) ", " flag_string : flag_string; \ uflag_count++; \ } \ - } while(0) + } while (0) CSUM_UFLAG_BUFFER(uflag_2, TCA_CSUM_UPDATE_FLAG_ICMP, "icmp"); CSUM_UFLAG_BUFFER(uflag_3, TCA_CSUM_UPDATE_FLAG_IGMP, "igmp"); CSUM_UFLAG_BUFFER(uflag_4, TCA_CSUM_UPDATE_FLAG_TCP, "tcp"); CSUM_UFLAG_BUFFER(uflag_5, TCA_CSUM_UPDATE_FLAG_UDP, "udp"); CSUM_UFLAG_BUFFER(uflag_6, TCA_CSUM_UPDATE_FLAG_UDPLITE, "udplite"); + CSUM_UFLAG_BUFFER(uflag_7, TCA_CSUM_UPDATE_FLAG_SCTP, "sctp"); if (!uflag_count) { uflag_1 = "?empty"; } - fprintf(f, "csum (%s%s%s%s%s%s) action %s\n", + fprintf(f, "csum (%s%s%s%s%s%s%s) ", uflag_1, uflag_2, uflag_3, - uflag_4, uflag_5, uflag_6, - action_n2a(sel->action, action_buf, sizeof(action_buf))); - fprintf(f, "\tindex %d ref %d bind %d", sel->index, sel->refcnt, sel->bindcnt); + uflag_4, uflag_5, uflag_6, uflag_7); + print_action_control(f, "action ", sel->action, "\n"); + fprintf(f, "\tindex %u ref %d bind %d", sel->index, sel->refcnt, + sel->bindcnt); if (show_stats) { if (tb[TCA_CSUM_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_CSUM_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } fprintf(f, "\n"); diff --git a/tc/m_ematch.c b/tc/m_ematch.c index 4c3acf82..e18a395b 100644 --- a/tc/m_ematch.c +++ b/tc/m_ematch.c @@ -33,7 +33,7 @@ static struct ematch_util *ematch_list; /* export to bison parser */ int ematch_argc; char **ematch_argv; -char *ematch_err = NULL; +char *ematch_err; struct ematch *ematch_root; static int begin_argc; @@ -177,9 +177,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree) for (t = tree; t; t = t->next) { struct rtattr *tail = NLMSG_TAIL(n); - struct tcf_ematch_hdr hdr = { - .flags = t->relation - }; + struct tcf_ematch_hdr hdr = { .flags = t->relation }; if (t->inverted) hdr.flags |= TCF_EM_INVERT; @@ -188,6 +186,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree) if (t->child) { __u32 r = t->child_ref; + addraw_l(n, MAX_MSG, &hdr, sizeof(hdr)); addraw_l(n, MAX_MSG, &r, sizeof(r)); } else { @@ -198,7 +197,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree) if (t->args == NULL) return -1; - strncpy(buf, (char*) t->args->data, sizeof(buf)-1); + strncpy(buf, (char *) t->args->data, sizeof(buf)-1); e = get_ematch_kind(buf); if (e == NULL) { fprintf(stderr, "Unknown ematch \"%s\"\n", @@ -218,7 +217,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree) return -1; } - tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail; + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; } return 0; @@ -353,8 +352,8 @@ int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) if (parse_tree(n, ematch_root) < 0) return -1; - tail_list->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail_list; - tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail; + tail_list->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail_list; + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; } *argc_p = ematch_argc; @@ -492,7 +491,7 @@ int print_ematch(FILE *fd, const struct rtattr *rta) return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]); } -struct bstr * bstr_alloc(const char *text) +struct bstr *bstr_alloc(const char *text) { struct bstr *b = calloc(1, sizeof(*b)); @@ -558,6 +557,7 @@ void print_ematch_tree(const struct ematch *tree) printf(")"); } else { struct bstr *b; + for (b = t->args; b; b = b->next) printf("%s%s", b->data, b->next ? " " : ""); } diff --git a/tc/m_estimator.c b/tc/m_estimator.c index 3dc8624f..87745cc2 100644 --- a/tc/m_estimator.c +++ b/tc/m_estimator.c @@ -38,7 +38,7 @@ int parse_estimator(int *p_argc, char ***p_argv, struct tc_estimator *est) { int argc = *p_argc; char **argv = *p_argv; - unsigned A, time_const; + unsigned int A, time_const; NEXT_ARG(); if (est->ewma_log) diff --git a/tc/m_gact.c b/tc/m_gact.c index 94bd5e73..38949e90 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -45,17 +45,21 @@ explain(void) #ifdef CONFIG_GACT_PROB fprintf(stderr, "Usage: ... gact <ACTION> [RAND] [INDEX]\n"); fprintf(stderr, - "Where: \tACTION := reclassify | drop | continue | pass \n" - "\tRAND := random <RANDTYPE> <ACTION> <VAL>\n" - "\tRANDTYPE := netrand | determ\n" + "Where: \tACTION := reclassify | drop | continue | pass | pipe |\n" + " \t goto chain <CHAIN_INDEX> | jump <JUMP_COUNT>\n" + "\tRAND := random <RANDTYPE> <ACTION> <VAL>\n" + "\tRANDTYPE := netrand | determ\n" "\tVAL : = value not exceeding 10000\n" + "\tJUMP_COUNT := Absolute jump from start of action list\n" "\tINDEX := index value used\n" "\n"); #else fprintf(stderr, "Usage: ... gact <ACTION> [INDEX]\n"); fprintf(stderr, - "Where: \tACTION := reclassify | drop | continue | pass \n" + "Where: \tACTION := reclassify | drop | continue | pass | pipe |\n" + " \t goto chain <CHAIN_INDEX> | jump <JUMP_COUNT>\n" "\tINDEX := index value used\n" + "\tJUMP_COUNT := Absolute jump from start of action list\n" "\n"); #endif } @@ -69,68 +73,31 @@ usage(void) } static int -get_act(char ***argv_p) -{ - char **argv = *argv_p; - - if (matches(*argv, "reclassify") == 0) { - return TC_ACT_RECLASSIFY; - } else if (matches(*argv, "drop") == 0 || matches(*argv, "shot") == 0) { - return TC_ACT_SHOT; - } else if (matches(*argv, "continue") == 0) { - return TC_ACT_UNSPEC; - } else if (matches(*argv, "pipe") == 0) { - return TC_ACT_PIPE; - } else if (matches(*argv, "pass") == 0 || matches(*argv, "ok") == 0) { - return TC_ACT_OK; - } else { - fprintf(stderr,"bad action type %s\n",*argv); - return -10; - } -} - -static int parse_gact(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; - int ok = 0; - int action = TC_POLICE_RECLASSIFY; - struct tc_gact p; + struct tc_gact p = { 0 }; #ifdef CONFIG_GACT_PROB int rd = 0; struct tc_gact_p pp; #endif struct rtattr *tail; - memset(&p, 0, sizeof (p)); - p.action = TC_POLICE_RECLASSIFY; - if (argc < 0) return -1; if (matches(*argv, "gact") == 0) { - ok++; - } else { - action = get_act(&argv); - if (action != -10) { - p.action = action; - ok++; - } else { - explain(); - return action; - } - } - - if (ok) { argc--; argv++; + } else if (parse_action_control(&argc, &argv, &p.action, false) == -1) { + usage(); /* does not return */ } #ifdef CONFIG_GACT_PROB - if (ok && argc > 0) { + if (argc > 0) { if (matches(*argv, "random") == 0) { rd = 1; NEXT_ARG(); @@ -145,21 +112,15 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, return -1; } - action = get_act(&argv); - if (action != -10) { /* FIXME */ - pp.paction = action; - } else { - explain(); - return -1; - } - argc--; - argv++; + if (parse_action_control(&argc, &argv, + &pp.paction, false) == -1) + usage(); if (get_u16(&pp.pval, *argv, 10)) { - fprintf(stderr, "Illegal probability val 0x%x\n",pp.pval); + fprintf(stderr, "Illegal probability val 0x%x\n", pp.pval); return -1; } if (pp.pval > 10000) { - fprintf(stderr, "Illegal probability val 0x%x\n",pp.pval); + fprintf(stderr, "Illegal probability val 0x%x\n", pp.pval); return -1; } argc--; @@ -179,21 +140,17 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, } argc--; argv++; - ok++; } else if (matches(*argv, "help") == 0) { usage(); } } - if (!ok) - return -1; - tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); - addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof (p)); + addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p)); #ifdef CONFIG_GACT_PROB if (rd) { - addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof (pp)); + addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp)); } #endif tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; @@ -204,11 +161,9 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, } static int -print_gact(struct action_util *au,FILE * f, struct rtattr *arg) +print_gact(struct action_util *au, FILE * f, struct rtattr *arg) { - SPRINT_BUF(b1); #ifdef CONFIG_GACT_PROB - SPRINT_BUF(b2); struct tc_gact_p *pp = NULL; struct tc_gact_p pp_dummy; #endif @@ -226,22 +181,27 @@ print_gact(struct action_util *au,FILE * f, struct rtattr *arg) } p = RTA_DATA(tb[TCA_GACT_PARMS]); - fprintf(f, "gact action %s", action_n2a(p->action, b1, sizeof (b1))); + fprintf(f, "gact "); + print_action_control(f, "action ", p->action, ""); #ifdef CONFIG_GACT_PROB - if (NULL != tb[TCA_GACT_PROB]) { + if (tb[TCA_GACT_PROB] != NULL) { pp = RTA_DATA(tb[TCA_GACT_PROB]); } else { /* need to keep consistent output */ - memset(&pp_dummy, 0, sizeof (pp_dummy)); + memset(&pp_dummy, 0, sizeof(pp_dummy)); pp = &pp_dummy; } - fprintf(f, "\n\t random type %s %s val %d",prob_n2a(pp->ptype), action_n2a(pp->paction, b2, sizeof (b2)), pp->pval); + fprintf(f, "\n\t random type %s", prob_n2a(pp->ptype)); + print_action_control(f, " ", pp->paction, " "); + fprintf(f, "val %d", pp->pval); #endif - fprintf(f, "\n\t index %d ref %d bind %d",p->index, p->refcnt, p->bindcnt); + fprintf(f, "\n\t index %u ref %d bind %d", p->index, p->refcnt, + p->bindcnt); if (show_stats) { if (tb[TCA_GACT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_GACT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } fprintf(f, "\n "); diff --git a/tc/m_ife.c b/tc/m_ife.c new file mode 100644 index 00000000..8d0fd31f --- /dev/null +++ b/tc/m_ife.c @@ -0,0 +1,336 @@ +/* + * m_ife.c IFE actions module + * + * This program is free software; you can distribute 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: J Hadi Salim (jhs@mojatatu.com) + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <linux/netdevice.h> + +#include "rt_names.h" +#include "utils.h" +#include "tc_util.h" +#include <linux/tc_act/tc_ife.h> + +static void ife_explain(void) +{ + fprintf(stderr, + "Usage:... ife {decode|encode} [{ALLOW|USE} ATTR] [dst DMAC] [src SMAC] [type TYPE] [CONTROL] [index INDEX]\n"); + fprintf(stderr, + "\tALLOW := Encode direction. Allows encoding specified metadata\n" + "\t\t e.g \"allow mark\"\n" + "\tUSE := Encode direction. Enforce Static encoding of specified metadata\n" + "\t\t e.g \"use mark 0x12\"\n" + "\tATTR := mark (32-bit), prio (32-bit), tcindex (16-bit)\n" + "\tDMAC := 6 byte Destination MAC address to encode\n" + "\tSMAC := optional 6 byte Source MAC address to encode\n" + "\tTYPE := optional 16 bit ethertype to encode\n" + "\tCONTROL := reclassify|pipe|drop|continue|ok\n" + "\tINDEX := optional IFE table index value used\n"); + fprintf(stderr, "encode is used for sending IFE packets\n"); + fprintf(stderr, "decode is used for receiving IFE packets\n"); +} + +static void ife_usage(void) +{ + ife_explain(); + exit(-1); +} + +static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) +{ + int argc = *argc_p; + char **argv = *argv_p; + int ok = 0; + struct tc_ife p = { 0 }; + struct rtattr *tail; + struct rtattr *tail2; + char dbuf[ETH_ALEN]; + char sbuf[ETH_ALEN]; + __u16 ife_type = 0; + int user_type = 0; + __u32 ife_prio = 0; + __u32 ife_prio_v = 0; + __u32 ife_mark = 0; + __u32 ife_mark_v = 0; + __u16 ife_tcindex = 0; + __u16 ife_tcindex_v = 0; + char *daddr = NULL; + char *saddr = NULL; + + if (argc <= 0) + return -1; + + while (argc > 0) { + if (matches(*argv, "ife") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "decode") == 0) { + p.flags = IFE_DECODE; /* readability aid */ + ok++; + } else if (matches(*argv, "encode") == 0) { + p.flags = IFE_ENCODE; + ok++; + } else if (matches(*argv, "allow") == 0) { + NEXT_ARG(); + if (matches(*argv, "mark") == 0) { + ife_mark = IFE_META_SKBMARK; + } else if (matches(*argv, "prio") == 0) { + ife_prio = IFE_META_PRIO; + } else if (matches(*argv, "tcindex") == 0) { + ife_tcindex = IFE_META_TCINDEX; + } else { + fprintf(stderr, "Illegal meta define <%s>\n", + *argv); + return -1; + } + } else if (matches(*argv, "use") == 0) { + NEXT_ARG(); + if (matches(*argv, "mark") == 0) { + NEXT_ARG(); + if (get_u32(&ife_mark_v, *argv, 0)) + invarg("ife mark val is invalid", + *argv); + } else if (matches(*argv, "prio") == 0) { + NEXT_ARG(); + if (get_u32(&ife_prio_v, *argv, 0)) + invarg("ife prio val is invalid", + *argv); + } else if (matches(*argv, "tcindex") == 0) { + NEXT_ARG(); + if (get_u16(&ife_tcindex_v, *argv, 0)) + invarg("ife tcindex val is invalid", + *argv); + } else { + fprintf(stderr, "Illegal meta use type <%s>\n", + *argv); + return -1; + } + } else if (matches(*argv, "type") == 0) { + NEXT_ARG(); + if (get_u16(&ife_type, *argv, 0)) + invarg("ife type is invalid", *argv); + fprintf(stderr, "IFE type 0x%04X\n", ife_type); + user_type = 1; + } else if (matches(*argv, "dst") == 0) { + NEXT_ARG(); + daddr = *argv; + if (sscanf(daddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + dbuf, dbuf + 1, dbuf + 2, + dbuf + 3, dbuf + 4, dbuf + 5) != 6) { + fprintf(stderr, "Invalid mac address %s\n", + daddr); + } + fprintf(stderr, "dst MAC address <%s>\n", daddr); + + } else if (matches(*argv, "src") == 0) { + NEXT_ARG(); + saddr = *argv; + if (sscanf(saddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + sbuf, sbuf + 1, sbuf + 2, + sbuf + 3, sbuf + 4, sbuf + 5) != 6) { + fprintf(stderr, "Invalid mac address %s\n", + saddr); + } + fprintf(stderr, "src MAC address <%s>\n", saddr); + } else if (matches(*argv, "help") == 0) { + ife_usage(); + } else { + break; + } + + argc--; + argv++; + } + + parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE); + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&p.index, *argv, 0)) { + fprintf(stderr, "ife: Illegal \"index\"\n"); + return -1; + } + ok++; + argc--; + argv++; + } + } + + if (!ok) { + fprintf(stderr, "IFE requires decode/encode specified\n"); + ife_usage(); + } + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_IFE_PARMS, &p, sizeof(p)); + + if (!(p.flags & IFE_ENCODE)) + goto skip_encode; + + if (daddr) + addattr_l(n, MAX_MSG, TCA_IFE_DMAC, dbuf, ETH_ALEN); + if (user_type) + addattr_l(n, MAX_MSG, TCA_IFE_TYPE, &ife_type, 2); + else + fprintf(stderr, "IFE type 0x%04X\n", ETH_P_IFE); + if (saddr) + addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN); + + tail2 = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, TCA_IFE_METALST, NULL, 0); + if (ife_mark || ife_mark_v) { + if (ife_mark_v) + addattr_l(n, MAX_MSG, IFE_META_SKBMARK, &ife_mark_v, 4); + else + addattr_l(n, MAX_MSG, IFE_META_SKBMARK, NULL, 0); + } + if (ife_prio || ife_prio_v) { + if (ife_prio_v) + addattr_l(n, MAX_MSG, IFE_META_PRIO, &ife_prio_v, 4); + else + addattr_l(n, MAX_MSG, IFE_META_PRIO, NULL, 0); + } + if (ife_tcindex || ife_tcindex_v) { + if (ife_tcindex_v) + addattr_l(n, MAX_MSG, IFE_META_TCINDEX, &ife_tcindex_v, + 2); + else + addattr_l(n, MAX_MSG, IFE_META_TCINDEX, NULL, 0); + } + + tail2->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail2; + +skip_encode: + tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) +{ + struct tc_ife *p = NULL; + struct rtattr *tb[TCA_IFE_MAX + 1]; + __u16 ife_type = 0; + __u32 mmark = 0; + __u16 mtcindex = 0; + __u32 mprio = 0; + int has_optional = 0; + SPRINT_BUF(b2); + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_IFE_MAX, arg); + + if (tb[TCA_IFE_PARMS] == NULL) { + fprintf(f, "[NULL ife parameters]"); + return -1; + } + p = RTA_DATA(tb[TCA_IFE_PARMS]); + + fprintf(f, "ife %s ", p->flags & IFE_ENCODE ? "encode" : "decode"); + print_action_control(f, "action ", p->action, " "); + + if (tb[TCA_IFE_TYPE]) { + ife_type = rta_getattr_u16(tb[TCA_IFE_TYPE]); + has_optional = 1; + fprintf(f, "type 0x%X ", ife_type); + } + + if (has_optional) + fprintf(f, "\n\t "); + + if (tb[TCA_IFE_METALST]) { + struct rtattr *metalist[IFE_META_MAX + 1]; + int len = 0; + + parse_rtattr_nested(metalist, IFE_META_MAX, + tb[TCA_IFE_METALST]); + + if (metalist[IFE_META_SKBMARK]) { + len = RTA_PAYLOAD(metalist[IFE_META_SKBMARK]); + if (len) { + mmark = rta_getattr_u32(metalist[IFE_META_SKBMARK]); + fprintf(f, "use mark %u ", mmark); + } else + fprintf(f, "allow mark "); + } + + if (metalist[IFE_META_TCINDEX]) { + len = RTA_PAYLOAD(metalist[IFE_META_TCINDEX]); + if (len) { + mtcindex = + rta_getattr_u16(metalist[IFE_META_TCINDEX]); + fprintf(f, "use tcindex %d ", mtcindex); + } else + fprintf(f, "allow tcindex "); + } + + if (metalist[IFE_META_PRIO]) { + len = RTA_PAYLOAD(metalist[IFE_META_PRIO]); + if (len) { + mprio = rta_getattr_u32(metalist[IFE_META_PRIO]); + fprintf(f, "use prio %u ", mprio); + } else + fprintf(f, "allow prio "); + } + + } + + if (tb[TCA_IFE_DMAC]) { + has_optional = 1; + fprintf(f, "dst %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_IFE_DMAC]), + RTA_PAYLOAD(tb[TCA_IFE_DMAC]), 0, b2, + sizeof(b2))); + + } + + if (tb[TCA_IFE_SMAC]) { + has_optional = 1; + fprintf(f, "src %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_IFE_SMAC]), + RTA_PAYLOAD(tb[TCA_IFE_SMAC]), 0, b2, + sizeof(b2))); + } + + fprintf(f, "\n\t index %u ref %d bind %d", p->index, p->refcnt, + p->bindcnt); + if (show_stats) { + if (tb[TCA_IFE_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_IFE_TM]); + + print_tm(f, tm); + } + } + + fprintf(f, "\n"); + + return 0; +} + +struct action_util ife_action_util = { + .id = "ife", + .parse_aopt = parse_ife, + .print_aopt = print_ife, +}; @@ -14,7 +14,6 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <linux/if.h> #include <iptables.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4/ip_tables.h> @@ -51,40 +50,29 @@ static struct option original_opts[] = { {0, 0, 0, 0} }; -static struct iptables_target *t_list = NULL; +static struct xtables_target *t_list; static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; +static unsigned int global_option_offset; #define OPTION_OFFSET 256 char *lib_dir; void -register_target(struct iptables_target *me) +xtables_register_target(struct xtables_target *me) { -/* fprintf(stderr, "\nDummy register_target %s \n", me->name); -*/ me->next = t_list; t_list = me; } -void -xtables_register_target(struct iptables_target *me) -{ - me->next = t_list; - t_list = me; -} - -void -exit_tryhelp(int status) +static void exit_tryhelp(int status) { fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", pname, pname); exit(status); } -void -exit_error(enum exittype status, char *msg, ...) +static void exit_error(enum xtables_exittype status, char *msg, ...) { va_list args; @@ -106,61 +94,6 @@ They should really have them as a library so i can link to them Email them next time i remember */ -char * -addr_to_dotted(const struct in_addr *addrp) -{ - static char buf[20]; - const unsigned char *bytep; - - bytep = (const unsigned char *) &(addrp->s_addr); - sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); - return buf; -} - -int string_to_number_ll(const char *s, unsigned long long min, - unsigned long long max, - unsigned long long *ret) -{ - unsigned long long number; - char *end; - - /* Handle hex, octal, etc. */ - errno = 0; - number = strtoull(s, &end, 0); - if (*end == '\0' && end != s) { - /* we parsed a number, let's see if we want this */ - if (errno != ERANGE && min <= number && (!max || number <= max)) { - *ret = number; - return 0; - } - } - return -1; -} - -int string_to_number_l(const char *s, unsigned long min, unsigned long max, - unsigned long *ret) -{ - int result; - unsigned long long number; - - result = string_to_number_ll(s, min, max, &number); - *ret = (unsigned long)number; - - return result; -} - -int string_to_number(const char *s, unsigned int min, unsigned int max, - unsigned int *ret) -{ - int result; - unsigned long number; - - result = string_to_number_l(s, min, max, &number); - *ret = (unsigned int)number; - - return result; -} - static void free_opts(struct option *local_opts) { if (local_opts != original_opts) { @@ -177,18 +110,18 @@ merge_options(struct option *oldopts, const struct option *newopts, struct option *merge; unsigned int num_old, num_new, i; - for (num_old = 0; oldopts[num_old].name; num_old++) ; - for (num_new = 0; newopts[num_new].name; num_new++) ; + for (num_old = 0; oldopts[num_old].name; num_old++); + for (num_new = 0; newopts[num_new].name; num_new++); *option_offset = global_option_offset + OPTION_OFFSET; - merge = malloc(sizeof (struct option) * (num_new + num_old + 1)); - memcpy(merge, oldopts, num_old * sizeof (struct option)); + merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); + memcpy(merge, oldopts, num_old * sizeof(struct option)); for (i = 0; i < num_new; i++) { merge[num_old + i] = newopts[i]; merge[num_old + i].val += *option_offset; } - memset(merge + num_old + num_new, 0, sizeof (struct option)); + memset(merge + num_old + num_new, 0, sizeof(struct option)); return merge; } @@ -205,10 +138,11 @@ fw_calloc(size_t count, size_t size) return p; } -static struct iptables_target * +static struct xtables_target * find_t(char *name) { - struct iptables_target *m; + struct xtables_target *m; + for (m = t_list; m; m = m->next) { if (strcmp(m->name, name) == 0) return m; @@ -217,29 +151,24 @@ find_t(char *name) return NULL; } -static struct iptables_target * +static struct xtables_target * get_target_name(const char *name) { void *handle; char *error; char *new_name, *lname; - struct iptables_target *m; - char path[strlen(lib_dir) + sizeof ("/libipt_.so") + strlen(name)]; + struct xtables_target *m; + char path[strlen(lib_dir) + sizeof("/libipt_.so") + strlen(name)]; #ifdef NO_SHARED_LIBS return NULL; #endif - new_name = malloc(strlen(name) + 1); - lname = malloc(strlen(name) + 1); - if (new_name) - memset(new_name, '\0', strlen(name) + 1); - else + new_name = calloc(1, strlen(name) + 1); + lname = calloc(1, strlen(name) + 1); + if (!new_name) exit_error(PARAMETER_PROBLEM, "get_target_name"); - - if (lname) - memset(lname, '\0', strlen(name) + 1); - else + if (!lname) exit_error(PARAMETER_PROBLEM, "get_target_name"); strcpy(new_name, name); @@ -247,6 +176,7 @@ get_target_name(const char *name) if (isupper(lname[0])) { int i; + for (i = 0; i < strlen(name); i++) { lname[i] = tolower(lname[i]); } @@ -254,6 +184,7 @@ get_target_name(const char *name) if (islower(new_name[0])) { int i; + for (i = 0; i < strlen(new_name); i++) { new_name[i] = toupper(new_name[i]); } @@ -268,12 +199,12 @@ get_target_name(const char *name) handle = dlopen(path, RTLD_LAZY); if (!handle) { - sprintf(path, "%s/libxt_%s.so", lib_dir , lname); + sprintf(path, "%s/libxt_%s.so", lib_dir, lname); handle = dlopen(path, RTLD_LAZY); } if (!handle) { - sprintf(path, "%s/libipt_%s.so", lib_dir , lname); + sprintf(path, "%s/libipt_%s.so", lib_dir, lname); handle = dlopen(path, RTLD_LAZY); } /* ok, lets give up .. */ @@ -288,12 +219,12 @@ get_target_name(const char *name) m = dlsym(handle, new_name); if ((error = dlerror()) != NULL) { - m = (struct iptables_target *) dlsym(handle, lname); + m = (struct xtables_target *) dlsym(handle, lname); if ((error = dlerror()) != NULL) { m = find_t(new_name); - if (NULL == m) { + if (m == NULL) { m = find_t(lname); - if (NULL == m) { + if (m == NULL) { fputs(error, stderr); fprintf(stderr, "\n"); dlclose(handle); @@ -310,42 +241,6 @@ get_target_name(const char *name) return m; } - -struct in_addr *dotted_to_addr(const char *dotted) -{ - static struct in_addr addr; - unsigned char *addrp; - char *p, *q; - unsigned int onebyte; - int i; - char buf[20]; - - /* copy dotted string, because we need to modify it */ - strncpy(buf, dotted, sizeof (buf) - 1); - addrp = (unsigned char *) &(addr.s_addr); - - p = buf; - for (i = 0; i < 3; i++) { - if ((q = strchr(p, '.')) == NULL) - return (struct in_addr *) NULL; - - *q = '\0'; - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[i] = (unsigned char) onebyte; - p = q + 1; - } - - /* we've checked 3 bytes, now we check the last one */ - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[3] = (unsigned char) onebyte; - - return &addr; -} - static void set_revision(char *name, u_int8_t revision) { /* Old kernel sources don't have ".revision" field, @@ -357,23 +252,20 @@ static void set_revision(char *name, u_int8_t revision) /* * we may need to check for version mismatch */ -int -build_st(struct iptables_target *target, struct ipt_entry_target *t) +static int build_st(struct xtables_target *target, struct ipt_entry_target *t) { - unsigned int nfcache = 0; - if (target) { size_t size; size = - IPT_ALIGN(sizeof (struct ipt_entry_target)) + target->size; + XT_ALIGN(sizeof(struct ipt_entry_target)) + target->size; - if (NULL == t) { + if (t == NULL) { target->t = fw_calloc(1, size); target->t->u.target_size = size; if (target->init != NULL) - target->init(target->t, &nfcache); + target->init(target->t); set_revision(target->t->u.user.name, target->revision); } else { target->t = t; @@ -385,10 +277,10 @@ build_st(struct iptables_target *target, struct ipt_entry_target *t) return -1; } -static int parse_ipt(struct action_util *a,int *argc_p, +static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { - struct iptables_target *m = NULL; + struct xtables_target *m = NULL; struct ipt_entry fw; struct rtattr *tail; int c; @@ -406,6 +298,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { int i; + for (i = 0; i < rargc; i++) { if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { break; @@ -415,7 +308,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (argc <= 2) { - fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); + fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc); return -1; } @@ -426,29 +319,29 @@ static int parse_ipt(struct action_util *a,int *argc_p, switch (c) { case 'j': m = get_target_name(optarg); - if (NULL != m) { + if (m != NULL) { - if (0 > build_st(m, NULL)) { - printf(" %s error \n", m->name); + if (build_st(m, NULL) < 0) { + printf(" %s error\n", m->name); return -1; } opts = merge_options(opts, m->extra_opts, &m->option_offset); } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } ok++; break; default: - memset(&fw, 0, sizeof (fw)); + memset(&fw, 0, sizeof(fw)); if (m) { m->parse(c - m->option_offset, argv, 0, &m->tflags, NULL, &m->t); } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } @@ -472,7 +365,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (!ok && !iok) { - fprintf(stderr," ipt Parser BAD!! (%s)\n", *argv); + fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); return -1; } @@ -482,6 +375,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { struct tcmsg *t = NLMSG_DATA(n); + if (t->tcm_parent != TC_H_ROOT && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { hook = NF_IP_PRE_ROUTING; @@ -522,11 +416,11 @@ static int parse_ipt(struct action_util *a,int *argc_p, optind = 0; free_opts(opts); /* Clear flags if target will be used again */ - m->tflags=0; - m->used=0; + m->tflags = 0; + m->used = 0; /* Free allocated memory */ - if (m->t) - free(m->t); + if (m->t) + free(m->t); return 0; @@ -534,7 +428,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } static int -print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) +print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) { struct rtattr *tb[TCA_IPT_MAX + 1]; struct ipt_entry_target *t = NULL; @@ -560,20 +454,22 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) return -1; } else { __u32 hook; + hook = rta_getattr_u32(tb[TCA_IPT_HOOK]); - fprintf(f, " hook: %s \n", ipthooks[hook]); + fprintf(f, " hook: %s\n", ipthooks[hook]); } if (tb[TCA_IPT_TARG] == NULL) { - fprintf(f, "\t[NULL ipt target parameters ] \n"); + fprintf(f, "\t[NULL ipt target parameters ]\n"); return -1; } else { - struct iptables_target *m = NULL; + struct xtables_target *m = NULL; + t = RTA_DATA(tb[TCA_IPT_TARG]); m = get_target_name(t->u.user.name); - if (NULL != m) { - if (0 > build_st(m, t)) { - fprintf(stderr, " %s error \n", m->name); + if (m != NULL) { + if (build_st(m, t) < 0) { + fprintf(stderr, " %s error\n", m->name); return -1; } @@ -591,21 +487,24 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) fprintf(f, " [NULL ipt target index ]\n"); } else { __u32 index; + index = rta_getattr_u32(tb[TCA_IPT_INDEX]); - fprintf(f, " \n\tindex %d", index); + fprintf(f, "\n\tindex %u", index); } if (tb[TCA_IPT_CNT]) { - struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);; + struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); + fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); } if (show_stats) { if (tb[TCA_IPT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } - fprintf(f, " \n"); + fprintf(f, "\n"); } free_opts(opts); @@ -614,7 +513,7 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) } struct action_util ipt_action_util = { - .id = "ipt", - .parse_aopt = parse_ipt, - .print_aopt = print_ipt, + .id = "ipt", + .parse_aopt = parse_ipt, + .print_aopt = print_ipt, }; diff --git a/tc/m_mirred.c b/tc/m_mirred.c index dc231d7c..2384bda1 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -29,12 +29,12 @@ static void explain(void) { - fprintf(stderr, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME> \n"); - fprintf(stderr, "where: \n"); + fprintf(stderr, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>\n"); + fprintf(stderr, "where:\n"); fprintf(stderr, "\tDIRECTION := <ingress | egress>\n"); fprintf(stderr, "\tACTION := <mirror | redirect>\n"); fprintf(stderr, "\tINDEX is the specific policy instance id\n"); - fprintf(stderr, "\tDEVICENAME is the devicename \n"); + fprintf(stderr, "\tDEVICENAME is the devicename\n"); } @@ -62,25 +62,36 @@ static const char *mirred_n2a(int action) } static int -parse_egress(struct action_util *a, int *argc_p, char ***argv_p, - int tca_id, struct nlmsghdr *n) +parse_direction(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; - int ok = 0, iok = 0, mirror=0,redir=0; - struct tc_mirred p; + int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0; + struct tc_mirred p = {}; struct rtattr *tail; - char d[16]; - - memset(d,0,sizeof(d)-1); - memset(&p,0,sizeof(struct tc_mirred)); + char d[16] = {}; while (argc > 0) { if (matches(*argv, "action") == 0) { break; - } else if (matches(*argv, "egress") == 0) { + } else if (!egress && matches(*argv, "egress") == 0) { + egress = 1; + if (ingress) { + fprintf(stderr, "Can't have both egress and ingress\n"); + return -1; + } + NEXT_ARG(); + ok++; + continue; + } else if (!ingress && matches(*argv, "ingress") == 0) { + ingress = 1; + if (egress) { + fprintf(stderr, "Can't have both ingress and egress\n"); + return -1; + } NEXT_ARG(); ok++; continue; @@ -98,26 +109,28 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, argv++; break; } - } else if(!ok) { - fprintf(stderr, "was expecting egress (%s)\n", *argv); + } else if (!ok) { + fprintf(stderr, "was expecting egress or ingress (%s)\n", *argv); break; } else if (!mirror && matches(*argv, "mirror") == 0) { - mirror=1; + mirror = 1; if (redir) { fprintf(stderr, "Can't have both mirror and redir\n"); return -1; } - p.eaction = TCA_EGRESS_MIRROR; + p.eaction = egress ? TCA_EGRESS_MIRROR : + TCA_INGRESS_MIRROR; p.action = TC_ACT_PIPE; ok++; } else if (!redir && matches(*argv, "redirect") == 0) { - redir=1; + redir = 1; if (mirror) { fprintf(stderr, "Can't have both mirror and redir\n"); return -1; } - p.eaction = TCA_EGRESS_REDIR; + p.eaction = egress ? TCA_EGRESS_REDIR : + TCA_INGRESS_REDIR; p.action = TC_ACT_STOLEN; ok++; } else if ((redir || mirror) && matches(*argv, "dev") == 0) { @@ -145,6 +158,7 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, if (d[0]) { int idx; + ll_init_map(&rth); if ((idx = ll_name_to_index(d)) == 0) { @@ -156,27 +170,8 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, } - if (argc && p.eaction == TCA_EGRESS_MIRROR) { - - if (matches(*argv, "reclassify") == 0) { - p.action = TC_POLICE_RECLASSIFY; - NEXT_ARG(); - } else if (matches(*argv, "pipe") == 0) { - p.action = TC_POLICE_PIPE; - NEXT_ARG(); - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - p.action = TC_POLICE_SHOT; - NEXT_ARG(); - } else if (matches(*argv, "continue") == 0) { - p.action = TC_POLICE_UNSPEC; - NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { - p.action = TC_POLICE_OK; - NEXT_ARG(); - } - - } + if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR) + parse_action_control(&argc, &argv, &p.action, false); if (argc) { if (iok && matches(*argv, "index") == 0) { @@ -197,7 +192,7 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); - addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof (p)); + addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; *argc_p = argc; @@ -215,32 +210,32 @@ parse_mirred(struct action_util *a, int *argc_p, char ***argv_p, char **argv = *argv_p; if (argc < 0) { - fprintf(stderr,"mirred bad argument count %d\n", argc); + fprintf(stderr, "mirred bad argument count %d\n", argc); return -1; } if (matches(*argv, "mirred") == 0) { NEXT_ARG(); } else { - fprintf(stderr,"mirred bad argument %s\n", *argv); + fprintf(stderr, "mirred bad argument %s\n", *argv); return -1; } - if (matches(*argv, "egress") == 0 || matches(*argv, "index") == 0) { - int ret = parse_egress(a, &argc, &argv, tca_id, n); + if (matches(*argv, "egress") == 0 || matches(*argv, "ingress") == 0 || + matches(*argv, "index") == 0) { + int ret = parse_direction(a, &argc, &argv, tca_id, n); + if (ret == 0) { *argc_p = argc; *argv_p = argv; return 0; } - } else if (matches(*argv, "ingress") == 0) { - fprintf(stderr,"mirred ingress not supported at the moment\n"); } else if (matches(*argv, "help") == 0) { usage(); } else { - fprintf(stderr,"mirred option not supported %s\n", *argv); + fprintf(stderr, "mirred option not supported %s\n", *argv); } return -1; @@ -248,12 +243,11 @@ parse_mirred(struct action_util *a, int *argc_p, char ***argv_p, } static int -print_mirred(struct action_util *au,FILE * f, struct rtattr *arg) +print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) { struct tc_mirred *p; struct rtattr *tb[TCA_MIRRED_MAX + 1]; const char *dev; - SPRINT_BUF(b1); if (arg == NULL) return -1; @@ -276,15 +270,18 @@ print_mirred(struct action_util *au,FILE * f, struct rtattr *arg) return -1; } - fprintf(f, "mirred (%s to device %s) %s", mirred_n2a(p->eaction), dev,action_n2a(p->action, b1, sizeof (b1))); + fprintf(f, "mirred (%s to device %s)", mirred_n2a(p->eaction), dev); + print_action_control(f, " ", p->action, ""); fprintf(f, "\n "); - fprintf(f, "\tindex %d ref %d bind %d",p->index,p->refcnt,p->bindcnt); + fprintf(f, "\tindex %u ref %d bind %d", p->index, p->refcnt, + p->bindcnt); if (show_stats) { if (tb[TCA_MIRRED_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } fprintf(f, "\n "); @@ -41,7 +41,7 @@ usage(void) } static int -parse_nat_args(int *argc_p, char ***argv_p,struct tc_nat *sel) +parse_nat_args(int *argc_p, char ***argv_p, struct tc_nat *sel) { int argc = *argc_p; char **argv = *argv_p; @@ -84,20 +84,18 @@ bad_val: static int parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { - struct tc_nat sel; + struct tc_nat sel = {}; int argc = *argc_p; char **argv = *argv_p; int ok = 0; struct rtattr *tail; - memset(&sel, 0, sizeof(sel)); - while (argc > 0) { if (matches(*argv, "nat") == 0) { NEXT_ARG(); if (parse_nat_args(&argc, &argv, &sel)) { - fprintf(stderr, "Illegal nat construct (%s) \n", + fprintf(stderr, "Illegal nat construct (%s)\n", *argv); explain(); return -1; @@ -117,30 +115,7 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct return -1; } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0) { - sel.action = TC_ACT_OK; - argc--; - argv++; - } - } + parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK); if (argc) { if (matches(*argv, "index") == 0) { @@ -165,13 +140,13 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct } static int -print_nat(struct action_util *au,FILE * f, struct rtattr *arg) +print_nat(struct action_util *au, FILE * f, struct rtattr *arg) { struct tc_nat *sel; struct rtattr *tb[TCA_NAT_MAX + 1]; char buf1[256]; char buf2[256]; - SPRINT_BUF(buf3); + int len; if (arg == NULL) @@ -188,17 +163,18 @@ print_nat(struct action_util *au,FILE * f, struct rtattr *arg) len = ffs(sel->mask); len = len ? 33 - len : 0; - fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ? - "egress" : "ingress", - format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), + fprintf(f, " nat %s %s/%d %s", sel->flags & TCA_NAT_FLAG_EGRESS ? + "egress" : "ingress", + format_host_r(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), len, - format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)), - action_n2a(sel->action, buf3, sizeof (buf3))); + format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2))); + print_action_control(f, " ", sel->action, ""); if (show_stats) { if (tb[TCA_NAT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 4fdd189d..5d89ab1d 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -28,45 +28,48 @@ #include "utils.h" #include "tc_util.h" #include "m_pedit.h" +#include "rt_names.h" static struct m_pedit_util *pedit_list; static int pedit_debug; -static void -explain(void) +static void explain(void) { - fprintf(stderr, "Usage: ... pedit munge <MUNGE>\n"); + fprintf(stderr, "Usage: ... pedit munge [ex] <MUNGE> [CONTROL]\n"); fprintf(stderr, "Where: MUNGE := <RAW>|<LAYERED>\n" - "\t<RAW>:= <OFFSETC>[ATC]<CMD>\n " - "\t\tOFFSETC:= offset <offval> <u8|u16|u32>\n " - "\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n " - "\t\tNOTE: offval is byte offset, must be multiple of 4\n " - "\t\tNOTE: maskval is a 32 bit hex number\n " - "\t\tNOTE: shiftval is a is a shift value\n " - "\t\tCMD:= clear | invert | set <setval>| retain\n " - "\t<LAYERED>:= ip <ipdata> | ip6 <ip6data> \n " - " \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata> \n" + "\t<RAW>:= <OFFSETC>[ATC]<CMD>\n \t\tOFFSETC:= offset <offval> <u8|u16|u32>\n" + "\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n" + "\t\tNOTE: offval is byte offset, must be multiple of 4\n" + "\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a shift value\n" + "\t\tCMD:= clear | invert | set <setval>| add <addval> | retain\n" + "\t<LAYERED>:= ip <ipdata> | ip6 <ip6data>\n" + " \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata>\n" + "\tCONTROL:= reclassify | pipe | drop | continue | pass |\n" + "\t goto chain <CHAIN_INDEX>\n" + "\tNOTE: if 'ex' is set, extended functionality will be supported (kernel >= 4.11)\n" "For Example usage look at the examples directory\n"); } -static void -usage(void) +static void usage(void) { explain(); exit(-1); } -static int -pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +static int pedit_parse_nopopt(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, + struct m_pedit_key *tkey) { int argc = *argc_p; char **argv = *argv_p; if (argc) { - fprintf(stderr, "Unknown action hence option \"%s\" is unparsable\n", *argv); - return -1; + fprintf(stderr, + "Unknown action hence option \"%s\" is unparsable\n", + *argv); + return -1; } return 0; @@ -78,7 +81,7 @@ static struct m_pedit_util *get_pedit_kind(const char *str) static void *pBODY; void *dlh; char buf[256]; - struct m_pedit_util *p; + struct m_pedit_util *p; for (p = pedit_list; p; p = p->next) { if (strcmp(p->id, str) == 0) @@ -107,19 +110,19 @@ reg: return p; noexist: - p = malloc(sizeof(*p)); + p = calloc(1, sizeof(*p)); if (p) { - memset(p, 0, sizeof(*p)); - strncpy(p->id, str, sizeof(p->id)-1); + strncpy(p->id, str, sizeof(p->id) - 1); p->parse_peopt = pedit_parse_nopopt; goto reg; } return p; } -int -pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +int pack_key(struct m_pedit_sel *_sel, struct m_pedit_key *tkey) { + struct tc_pedit_sel *sel = &_sel->sel; + struct m_pedit_key_ex *keys_ex = _sel->keys_ex; int hwm = sel->nkeys; if (hwm >= MAX_OFFS) @@ -136,13 +139,25 @@ pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) sel->keys[hwm].at = tkey->at; sel->keys[hwm].offmask = tkey->offmask; sel->keys[hwm].shift = tkey->shift; + + if (_sel->extended) { + keys_ex[hwm].htype = tkey->htype; + keys_ex[hwm].cmd = tkey->cmd; + } else { + if (tkey->htype != TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK || + tkey->cmd != TCA_PEDIT_KEY_EX_CMD_SET) { + fprintf(stderr, + "Munge parameters not supported. Use 'pedit ex munge ...'.\n"); + return -1; + } + } + sel->nkeys++; return 0; } - -int -pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +int pack_key32(__u32 retain, struct m_pedit_sel *sel, + struct m_pedit_key *tkey) { if (tkey->off > (tkey->off & ~3)) { fprintf(stderr, @@ -152,16 +167,14 @@ pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) tkey->val = htonl(tkey->val & retain); tkey->mask = htonl(tkey->mask | ~retain); - /* jamal remove this - it is not necessary given the if check above */ - tkey->off &= ~3; - return pack_key(sel,tkey); + return pack_key(sel, tkey); } -int -pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +int pack_key16(__u32 retain, struct m_pedit_sel *sel, + struct m_pedit_key *tkey) { int ind, stride; - __u32 m[4] = {0xFFFF0000,0xFF0000FF,0x0000FFFF}; + __u32 m[4] = { 0x0000FFFF, 0xFF0000FF, 0xFFFF0000 }; if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) { fprintf(stderr, "pack_key16 bad value\n"); @@ -171,53 +184,107 @@ pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) ind = tkey->off & 3; if (ind == 3) { - fprintf(stderr, "pack_key16 bad index value %d\n",ind); + fprintf(stderr, "pack_key16 bad index value %d\n", ind); return -1; } - stride = 8 * ind; - tkey->val = htons(tkey->val); - tkey->val <<= stride; - tkey->mask <<= stride; - retain <<= stride; - tkey->mask = retain|m[ind]; + stride = 8 * (2 - ind); + tkey->val = htonl((tkey->val & retain) << stride); + tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]); tkey->off &= ~3; if (pedit_debug) - printf("pack_key16: Final val %08x mask %08x \n",tkey->val,tkey->mask); - return pack_key(sel,tkey); + printf("pack_key16: Final val %08x mask %08x\n", + tkey->val, tkey->mask); + return pack_key(sel, tkey); } -int -pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +int pack_key8(__u32 retain, struct m_pedit_sel *sel, struct m_pedit_key *tkey) { int ind, stride; - __u32 m[4] = {0xFFFFFF00,0xFFFF00FF,0xFF00FFFF,0x00FFFFFF}; + __u32 m[4] = { 0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00 }; if (tkey->val > 0xFF || tkey->mask > 0xFF) { - fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", tkey->val, tkey->mask); + fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", + tkey->val, tkey->mask); return -1; } ind = tkey->off & 3; - stride = 8 * ind; - tkey->val <<= stride; - tkey->mask <<= stride; - retain <<= stride; - tkey->mask = retain|m[ind]; + stride = 8 * (3 - ind); + tkey->val = htonl((tkey->val & retain) << stride); + tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]); tkey->off &= ~3; if (pedit_debug) - printf("pack_key8: Final word off %d val %08x mask %08x \n",tkey->off , tkey->val,tkey->mask); - return pack_key(sel,tkey); + printf("pack_key8: Final word off %d val %08x mask %08x\n", + tkey->off, tkey->val, tkey->mask); + return pack_key(sel, tkey); +} + +static int pack_mac(struct m_pedit_sel *sel, struct m_pedit_key *tkey, + __u8 *mac) +{ + int ret = 0; + + if (!(tkey->off & 0x3)) { + tkey->mask = 0; + tkey->val = ntohl(*((__u32 *)mac)); + ret |= pack_key32(~0, sel, tkey); + + tkey->off += 4; + tkey->mask = 0; + tkey->val = ntohs(*((__u16 *)&mac[4])); + ret |= pack_key16(~0, sel, tkey); + } else if (!(tkey->off & 0x1)) { + tkey->mask = 0; + tkey->val = ntohs(*((__u16 *)mac)); + ret |= pack_key16(~0, sel, tkey); + + tkey->off += 4; + tkey->mask = 0; + tkey->val = ntohl(*((__u32 *)(mac + 2))); + ret |= pack_key32(~0, sel, tkey); + } else { + fprintf(stderr, + "pack_mac: mac offsets must begin in 32bit or 16bit boundaries\n"); + return -1; + } + + return ret; +} + +static int pack_ipv6(struct m_pedit_sel *sel, struct m_pedit_key *tkey, + __u32 *ipv6) +{ + int ret = 0; + int i; + + if (tkey->off & 0x3) { + fprintf(stderr, + "pack_ipv6: IPv6 offsets must begin in 32bit boundaries\n"); + return -1; + } + + for (i = 0; i < 4; i++) { + tkey->mask = 0; + tkey->val = ntohl(ipv6[i]); + + ret = pack_key32(~0, sel, tkey); + if (ret) + return ret; + + tkey->off += 4; + } + + return 0; } -int -parse_val(int *argc_p, char ***argv_p, __u32 * val, int type) +int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type) { int argc = *argc_p; char **argv = *argv_p; @@ -225,32 +292,51 @@ parse_val(int *argc_p, char ***argv_p, __u32 * val, int type) if (argc <= 0) return -1; - if (TINT == type) - return get_integer((int *) val, *argv, 0); + if (type == TINT) + return get_integer((int *)val, *argv, 0); - if (TU32 == type) + if (type == TU32) return get_u32(val, *argv, 0); - if (TIPV4 == type) { + if (type == TIPV4) { inet_prefix addr; - if (get_prefix_1(&addr, *argv, AF_INET)) { + + if (get_prefix_1(&addr, *argv, AF_INET)) return -1; - } - *val=addr.data[0]; + + *val = addr.data[0]; return 0; } - if (TIPV6 == type) { - /* not implemented yet */ - return -1; + + if (type == TIPV6) { + inet_prefix addr; + + if (get_prefix_1(&addr, *argv, AF_INET6)) + return -1; + + memcpy(val, addr.data, addr.bytelen); + + return 0; + } + + if (type == TMAC) { +#define MAC_ALEN 6 + int ret = ll_addr_a2n((char *)val, MAC_ALEN, *argv); + + if (ret == MAC_ALEN) + return 0; } return -1; } -int -parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, + struct m_pedit_sel *sel, struct m_pedit_key *tkey) { - __u32 mask = 0, val = 0; + __u32 mask[4] = { 0 }; + __u32 val[4] = { 0 }; + __u32 *m = &mask[0]; + __u32 *v = &val[0]; __u32 o = 0xFF; int res = -1; int argc = *argc_p; @@ -260,7 +346,8 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct t return -1; if (pedit_debug) - printf("parse_cmd argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len); + printf("parse_cmd argc %d %s offset %d length %d\n", + argc, *argv, tkey->off, len); if (len == 2) o = 0xFFFF; @@ -268,57 +355,87 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct t o = 0xFFFFFFFF; if (matches(*argv, "invert") == 0) { - retain = val = mask = o; - } else if (matches(*argv, "set") == 0) { + *v = *m = o; + } else if (matches(*argv, "set") == 0 || + matches(*argv, "add") == 0) { + if (matches(*argv, "add") == 0) + tkey->cmd = TCA_PEDIT_KEY_EX_CMD_ADD; + + if (!sel->extended && tkey->cmd) { + fprintf(stderr, + "Non extended mode. only 'set' command is supported\n"); + return -1; + } + NEXT_ARG(); - if (parse_val(&argc, &argv, &val, type)) + if (parse_val(&argc, &argv, val, type)) return -1; } else if (matches(*argv, "preserve") == 0) { - retain = mask = o; + retain = 0; } else { if (matches(*argv, "clear") != 0) return -1; } - argc--; argv++; + argc--; + argv++; if (argc && matches(*argv, "retain") == 0) { NEXT_ARG(); if (parse_val(&argc, &argv, &retain, TU32)) return -1; - argc--; argv++; + argc--; + argv++; + } + + if (len > 4 && retain != ~0) { + fprintf(stderr, + "retain is not supported for fields longer the 32 bits\n"); + return -1; } - tkey->val = val; + if (type == TMAC) { + res = pack_mac(sel, tkey, (__u8 *)val); + goto done; + } + + if (type == TIPV6) { + res = pack_ipv6(sel, tkey, val); + goto done; + } + + tkey->val = *v; + tkey->mask = *m; + + if (type == TIPV4) + tkey->val = ntohl(tkey->val); if (len == 1) { - tkey->mask = 0xFF; - res = pack_key8(retain,sel,tkey); + res = pack_key8(retain, sel, tkey); goto done; } if (len == 2) { - tkey->mask = mask; - res = pack_key16(retain,sel,tkey); + res = pack_key16(retain, sel, tkey); goto done; } if (len == 4) { - tkey->mask = mask; - res = pack_key32(retain,sel,tkey); + res = pack_key32(retain, sel, tkey); goto done; } return -1; done: if (pedit_debug) - printf("parse_cmd done argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len); + printf("parse_cmd done argc %d %s offset %d length %d\n", + argc, *argv, tkey->off, len); *argc_p = argc; *argv_p = argv; return res; } -int -parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +int parse_offset(int *argc_p, char ***argv_p, struct m_pedit_sel *sel, + struct m_pedit_key *tkey) { int off; __u32 len, retain; @@ -339,7 +456,6 @@ parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedi if (argc <= 0) return -1; - if (matches(*argv, "u32") == 0) { len = 4; retain = 0xFFFFFFFF; @@ -347,12 +463,12 @@ parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedi } if (matches(*argv, "u16") == 0) { len = 2; - retain = 0x0; + retain = 0xffff; goto done; } if (matches(*argv, "u8") == 0) { len = 1; - retain = 0x0; + retain = 0xff; goto done; } @@ -365,7 +481,7 @@ done: /* [at <someval> offmask <maskval> shift <shiftval>] */ if (matches(*argv, "at") == 0) { - __u32 atv=0,offmask=0x0,shift=0; + __u32 atv = 0, offmask = 0x0, shift = 0; NEXT_ARG(); if (get_u32(&atv, *argv, 0)) @@ -387,17 +503,16 @@ done: NEXT_ARG(); } - res = parse_cmd(&argc, &argv, len, TU32,retain,sel,tkey); + res = parse_cmd(&argc, &argv, len, TU32, retain, sel, tkey); *argc_p = argc; *argv_p = argv; return res; } -static int -parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel) +static int parse_munge(int *argc_p, char ***argv_p, struct m_pedit_sel *sel) { - struct tc_pedit_key tkey; + struct m_pedit_key tkey = {}; int argc = *argc_p; char **argv = *argv_p; int res = -1; @@ -405,25 +520,24 @@ parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel) if (argc <= 0) return -1; - memset(&tkey, 0, sizeof(tkey)); - if (matches(*argv, "offset") == 0) { NEXT_ARG(); - res = parse_offset(&argc, &argv,sel,&tkey); + res = parse_offset(&argc, &argv, sel, &tkey); goto done; } else { char k[16]; struct m_pedit_util *p = NULL; - strncpy(k, *argv, sizeof (k) - 1); + strncpy(k, *argv, sizeof(k) - 1); - if (argc > 0 ) { + if (argc > 0) { p = get_pedit_kind(k); - if (NULL == p) + if (p == NULL) goto bad_val; - res = p->parse_peopt(&argc, &argv, sel,&tkey); + NEXT_ARG(); + res = p->parse_peopt(&argc, &argv, sel, &tkey); if (res < 0) { - fprintf(stderr,"bad pedit parsing\n"); + fprintf(stderr, "bad pedit parsing\n"); goto bad_val; } goto done; @@ -440,39 +554,108 @@ done: return res; } -int -parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) +static int pedit_keys_ex_getattr(struct rtattr *attr, + struct m_pedit_key_ex *keys_ex, int n) { - struct { - struct tc_pedit_sel sel; - struct tc_pedit_key keys[MAX_OFFS]; - } sel; + struct rtattr *i; + int rem = RTA_PAYLOAD(attr); + struct rtattr *tb[TCA_PEDIT_KEY_EX_MAX + 1]; + struct m_pedit_key_ex *k = keys_ex; + + for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { + if (!n) + return -1; + + if (i->rta_type != TCA_PEDIT_KEY_EX) + return -1; + + parse_rtattr_nested(tb, TCA_PEDIT_KEY_EX_MAX, i); + + k->htype = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_HTYPE]); + k->cmd = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_CMD]); + + k++; + n--; + } + + return !!n; +} + +static int pedit_keys_ex_addattr(struct m_pedit_sel *sel, struct nlmsghdr *n) +{ + struct m_pedit_key_ex *k = sel->keys_ex; + struct rtattr *keys_start; + int i; + + if (!sel->extended) + return 0; + + keys_start = addattr_nest(n, MAX_MSG, TCA_PEDIT_KEYS_EX | NLA_F_NESTED); + + for (i = 0; i < sel->sel.nkeys; i++) { + struct rtattr *key_start; + + key_start = addattr_nest(n, MAX_MSG, + TCA_PEDIT_KEY_EX | NLA_F_NESTED); + + if (addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_HTYPE, k->htype) || + addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_CMD, k->cmd)) { + return -1; + } + + addattr_nest_end(n, key_start); + + k++; + } + + addattr_nest_end(n, keys_start); + + return 0; +} + +int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, + struct nlmsghdr *n) +{ + struct m_pedit_sel sel = {}; int argc = *argc_p; char **argv = *argv_p; int ok = 0, iok = 0; struct rtattr *tail; - memset(&sel, 0, sizeof(sel)); - while (argc > 0) { if (pedit_debug > 1) - fprintf(stderr, "while pedit (%d:%s)\n",argc, *argv); + fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv); if (matches(*argv, "pedit") == 0) { NEXT_ARG(); ok++; + + if (matches(*argv, "ex") == 0) { + if (ok > 1) { + fprintf(stderr, + "'ex' must be before first 'munge'\n"); + explain(); + return -1; + } + sel.extended = true; + NEXT_ARG(); + } + continue; } else if (matches(*argv, "help") == 0) { usage(); } else if (matches(*argv, "munge") == 0) { if (!ok) { - fprintf(stderr, "Illegal pedit construct (%s) \n", *argv); + fprintf(stderr, "Bad pedit construct (%s)\n", + *argv); explain(); return -1; } NEXT_ARG(); - if (parse_munge(&argc, &argv,&sel.sel)) { - fprintf(stderr, "Illegal pedit construct (%s) \n", *argv); + + if (parse_munge(&argc, &argv, &sel)) { + fprintf(stderr, "Bad pedit construct (%s)\n", + *argv); explain(); return -1; } @@ -488,25 +671,7 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru return -1; } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.sel.action = TC_ACT_RECLASSIFY; - NEXT_ARG(); - } else if (matches(*argv, "pipe") == 0) { - sel.sel.action = TC_ACT_PIPE; - NEXT_ARG(); - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.sel.action = TC_ACT_SHOT; - NEXT_ARG(); - } else if (matches(*argv, "continue") == 0) { - sel.sel.action = TC_ACT_UNSPEC; - NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { - sel.sel.action = TC_ACT_OK; - NEXT_ARG(); - } - } + parse_action_control_dflt(&argc, &argv, &sel.sel.action, false, TC_ACT_OK); if (argc) { if (matches(*argv, "index") == 0) { @@ -523,63 +688,147 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); - addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS,&sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_pedit_key)); - tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; + if (!sel.extended) { + addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel, + sizeof(sel.sel) + + sel.sel.nkeys * sizeof(struct tc_pedit_key)); + } else { + addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS_EX, &sel, + sizeof(sel.sel) + + sel.sel.nkeys * sizeof(struct tc_pedit_key)); + + pedit_keys_ex_addattr(&sel, n); + } + + tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; *argc_p = argc; *argv_p = argv; return 0; } -int -print_pedit(struct action_util *au,FILE * f, struct rtattr *arg) +const char *pedit_htype_str[] = { + [TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK] = "", + [TCA_PEDIT_KEY_EX_HDR_TYPE_ETH] = "eth", + [TCA_PEDIT_KEY_EX_HDR_TYPE_IP4] = "ipv4", + [TCA_PEDIT_KEY_EX_HDR_TYPE_IP6] = "ipv6", + [TCA_PEDIT_KEY_EX_HDR_TYPE_TCP] = "tcp", + [TCA_PEDIT_KEY_EX_HDR_TYPE_UDP] = "udp", +}; + +static void print_pedit_location(FILE *f, + enum pedit_header_type htype, __u32 off) +{ + if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) { + fprintf(f, "%d", (unsigned int)off); + return; + } + + if (htype < ARRAY_SIZE(pedit_htype_str)) + fprintf(f, "%s", pedit_htype_str[htype]); + else + fprintf(f, "unknown(%d)", htype); + + fprintf(f, "%c%d", (int)off >= 0 ? '+' : '-', abs((int)off)); +} + +int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg) { struct tc_pedit_sel *sel; struct rtattr *tb[TCA_PEDIT_MAX + 1]; - SPRINT_BUF(b1); + struct m_pedit_key_ex *keys_ex = NULL; if (arg == NULL) return -1; parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg); - if (tb[TCA_PEDIT_PARMS] == NULL) { + if (!tb[TCA_PEDIT_PARMS] && !tb[TCA_PEDIT_PARMS_EX]) { fprintf(f, "[NULL pedit parameters]"); return -1; } - sel = RTA_DATA(tb[TCA_PEDIT_PARMS]); - fprintf(f, " pedit action %s keys %d\n ", action_n2a(sel->action, b1, sizeof (b1)),sel->nkeys); - fprintf(f, "\t index %d ref %d bind %d", sel->index,sel->refcnt, sel->bindcnt); + if (tb[TCA_PEDIT_PARMS]) { + sel = RTA_DATA(tb[TCA_PEDIT_PARMS]); + } else { + int err; + + sel = RTA_DATA(tb[TCA_PEDIT_PARMS_EX]); + + if (!tb[TCA_PEDIT_KEYS_EX]) { + fprintf(f, "Netlink error\n"); + return -1; + } + + keys_ex = calloc(sel->nkeys, sizeof(*keys_ex)); + if (!keys_ex) { + fprintf(f, "Out of memory\n"); + return -1; + } + + err = pedit_keys_ex_getattr(tb[TCA_PEDIT_KEYS_EX], keys_ex, + sel->nkeys); + if (err) { + fprintf(f, "Netlink error\n"); + + free(keys_ex); + return -1; + } + } + + fprintf(f, " pedit "); + print_action_control(f, "action ", sel->action, " "); + fprintf(f,"keys %d\n ", sel->nkeys); + fprintf(f, "\t index %u ref %d bind %d", sel->index, sel->refcnt, + sel->bindcnt); if (show_stats) { if (tb[TCA_PEDIT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } if (sel->nkeys) { int i; struct tc_pedit_key *key = sel->keys; + struct m_pedit_key_ex *key_ex = keys_ex; + + for (i = 0; i < sel->nkeys; i++, key++) { + enum pedit_header_type htype = + TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK; + enum pedit_cmd cmd = TCA_PEDIT_KEY_EX_CMD_SET; - for (i=0; i<sel->nkeys; i++, key++) { - fprintf(f, "\n\t key #%d",i); - fprintf(f, " at %d: val %08x mask %08x", - (unsigned int)key->off, - (unsigned int)ntohl(key->val), - (unsigned int)ntohl(key->mask)); + if (keys_ex) { + htype = key_ex->htype; + cmd = key_ex->cmd; + + key_ex++; + } + + fprintf(f, "\n\t key #%d", i); + + fprintf(f, " at "); + + print_pedit_location(f, htype, key->off); + + fprintf(f, ": %s %08x mask %08x", + cmd ? "add" : "val", + (unsigned int)ntohl(key->val), + (unsigned int)ntohl(key->mask)); } } else { - fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,sel->nkeys); + fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index, + sel->nkeys); } - fprintf(f, "\n "); + + free(keys_ex); return 0; } -int -pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats) +int pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats) { return 0; } diff --git a/tc/m_pedit.h b/tc/m_pedit.h index 1698c954..0bc02971 100644 --- a/tc/m_pedit.h +++ b/tc/m_pedit.h @@ -32,6 +32,7 @@ #define TIPV6 2 #define TINT 3 #define TU32 4 +#define TMAC 5 #define RU32 0xFFFFFFFF #define RU16 0xFFFF @@ -39,24 +40,55 @@ #define PEDITKINDSIZ 16 -struct m_pedit_util -{ +struct m_pedit_key { + __u32 mask; /* AND */ + __u32 val; /*XOR */ + __u32 off; /*offset */ + __u32 at; + __u32 offmask; + __u32 shift; + + enum pedit_header_type htype; + enum pedit_cmd cmd; +}; + +struct m_pedit_key_ex { + enum pedit_header_type htype; + enum pedit_cmd cmd; +}; + +struct m_pedit_sel { + struct tc_pedit_sel sel; + struct tc_pedit_key keys[MAX_OFFS]; + struct m_pedit_key_ex keys_ex[MAX_OFFS]; + bool extended; +}; + +struct m_pedit_util { struct m_pedit_util *next; char id[PEDITKINDSIZ]; - int (*parse_peopt)(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); + int (*parse_peopt)(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, + struct m_pedit_key *tkey); }; - -extern int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); -extern int pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); -extern int pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); -extern int pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); -extern int pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); -extern int parse_val(int *argc_p, char ***argv_p, __u32 * val, int type); -extern int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); -extern int parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); -int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); -extern int print_pedit(struct action_util *au,FILE * f, struct rtattr *arg); -extern int pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats); +extern int pack_key(struct m_pedit_sel *sel, struct m_pedit_key *tkey); +extern int pack_key32(__u32 retain, struct m_pedit_sel *sel, + struct m_pedit_key *tkey); +extern int pack_key16(__u32 retain, struct m_pedit_sel *sel, + struct m_pedit_key *tkey); +extern int pack_key8(__u32 retain, struct m_pedit_sel *sel, + struct m_pedit_key *tkey); +extern int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type); +extern int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, + __u32 retain, + struct m_pedit_sel *sel, struct m_pedit_key *tkey); +extern int parse_offset(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, struct m_pedit_key *tkey); +int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n); +extern int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg); +extern int pedit_print_xstats(struct action_util *au, FILE *f, + struct rtattr *xstats); #endif diff --git a/tc/m_police.c b/tc/m_police.c index 915f1a51..86117db0 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -36,11 +36,13 @@ static void usage(void) { fprintf(stderr, "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n"); fprintf(stderr, " [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n"); - fprintf(stderr, " [ linklayer TYPE ] [ ACTIONTERM ]\n"); + fprintf(stderr, " [ linklayer TYPE ] [ CONTROL ]\n"); - fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT] \n"); - fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue \n"); - fprintf(stderr, "Where: pipe is only valid for new syntax \n"); + fprintf(stderr, "Where: CONTROL := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT]\n"); + fprintf(stderr, " Define how to handle packets which exceed (<EXCEEDACT>)\n"); + fprintf(stderr, " or conform (<NOTEXCEEDACT>) the configured bandwidth limit.\n"); + fprintf(stderr, " EXCEEDACT/NOTEXCEEDACT := { pipe | ok | reclassify | drop | continue |\n"); + fprintf(stderr, " goto chain <CHAIN_INDEX> }\n"); exit(-1); } @@ -49,98 +51,24 @@ static void explain1(char *arg) fprintf(stderr, "Illegal \"%s\"\n", arg); } -static const char *police_action_n2a(int action, char *buf, int len) -{ - switch (action) { - case -1: - return "continue"; - break; - case TC_POLICE_OK: - return "pass"; - break; - case TC_POLICE_SHOT: - return "drop"; - break; - case TC_POLICE_RECLASSIFY: - return "reclassify"; - case TC_POLICE_PIPE: - return "pipe"; - default: - snprintf(buf, len, "%d", action); - return buf; - } -} - -static int police_action_a2n(const char *arg, int *result) -{ - int res; - - if (matches(arg, "continue") == 0) - res = -1; - else if (matches(arg, "drop") == 0) - res = TC_POLICE_SHOT; - else if (matches(arg, "shot") == 0) - res = TC_POLICE_SHOT; - else if (matches(arg, "pass") == 0) - res = TC_POLICE_OK; - else if (strcmp(arg, "ok") == 0) - 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) - return -1; - } - *result = res; - return 0; -} - - -static int get_police_result(int *action, int *result, char *arg) -{ - char *p = strchr(arg, '/'); - - if (p) - *p = 0; - - if (police_action_a2n(arg, action)) { - if (p) - *p = '/'; - return -1; - } - - if (p) { - *p = '/'; - if (police_action_a2n(p+1, result)) - return -1; - } - return 0; -} - - -int act_parse_police(struct action_util *a,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; int res = -1; - int ok=0; - struct tc_police p; + int ok = 0; + struct tc_police p = { .action = TC_POLICE_RECLASSIFY }; __u32 rtab[256]; __u32 ptab[256]; __u32 avrate = 0; int presult = 0; - unsigned buffer=0, mtu=0, mpu=0; - unsigned short overhead=0; + unsigned buffer = 0, mtu = 0, mpu = 0; + unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ - int Rcell_log=-1, Pcell_log = -1; + int Rcell_log = -1, Pcell_log = -1; struct rtattr *tail; - memset(&p, 0, sizeof(p)); - p.action = TC_POLICE_RECLASSIFY; - if (a) /* new way of doing things */ NEXT_ARG(); @@ -218,23 +146,20 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_ explain1("peakrate"); return -1; } - } else if (matches(*argv, "reclassify") == 0) { - p.action = TC_POLICE_RECLASSIFY; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - p.action = TC_POLICE_SHOT; - } else if (matches(*argv, "continue") == 0) { - p.action = TC_POLICE_UNSPEC; - } else if (matches(*argv, "pass") == 0) { - p.action = TC_POLICE_OK; - } else if (matches(*argv, "pipe") == 0) { - p.action = TC_POLICE_PIPE; + } else if (matches(*argv, "reclassify") == 0 || + matches(*argv, "drop") == 0 || + matches(*argv, "shot") == 0 || + matches(*argv, "continue") == 0 || + matches(*argv, "pass") == 0 || + matches(*argv, "pipe") == 0 || + matches(*argv, "goto") == 0) { + if (parse_action_control(&argc, &argv, &p.action, false)) + return -1; } else if (strcmp(*argv, "conform-exceed") == 0) { NEXT_ARG(); - if (get_police_result(&p.action, &presult, *argv)) { - fprintf(stderr, "Illegal \"action\"\n"); + if (parse_action_control_slash(&argc, &argv, &p.action, + &presult, true)) return -1; - } } else if (matches(*argv, "overhead") == 0) { NEXT_ARG(); if (get_u16(&overhead, *argv, 10)) { @@ -257,10 +182,21 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_ if (!ok) return -1; - if (p.rate.rate && !buffer) { + if (p.rate.rate && avrate) + return -1; + + /* Must at least do late binding, use TB or ewma policing */ + if (!p.rate.rate && !avrate && !p.index) { + fprintf(stderr, "\"rate\" or \"avrate\" MUST be specified.\n"); + return -1; + } + + /* When the TB policer is used, burst is required */ + if (p.rate.rate && !buffer && !avrate) { fprintf(stderr, "\"burst\" requires \"rate\".\n"); return -1; } + if (p.peakrate.rate) { if (!p.rate.rate) { fprintf(stderr, "\"peakrate\" requires \"rate\".\n"); @@ -275,8 +211,9 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_ if (p.rate.rate) { p.rate.mpu = mpu; p.rate.overhead = overhead; - if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, linklayer) < 0) { - fprintf(stderr, "TBF: failed to calculate rate table.\n"); + if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, + linklayer) < 0) { + fprintf(stderr, "POLICE: failed to calculate rate table.\n"); return -1; } p.burst = tc_calc_xmittime(p.rate.rate, buffer); @@ -285,7 +222,8 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_ if (p.peakrate.rate) { p.peakrate.mpu = mpu; p.peakrate.overhead = overhead; - if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) { + if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, + linklayer) < 0) { fprintf(stderr, "POLICE: failed to calculate peak rate table.\n"); return -1; } @@ -297,7 +235,7 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_ if (p.rate.rate) addattr_l(n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024); if (p.peakrate.rate) - addattr_l(n, MAX_MSG, TCA_POLICE_PEAKRATE, ptab, 1024); + addattr_l(n, MAX_MSG, TCA_POLICE_PEAKRATE, ptab, 1024); if (avrate) addattr32(n, MAX_MSG, TCA_POLICE_AVRATE, avrate); if (presult) @@ -313,17 +251,16 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_ 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); + return act_parse_police(NULL, argc_p, argv_p, tca_id, n); } -int -print_police(struct action_util *a, FILE *f, struct rtattr *arg) +int print_police(struct action_util *a, FILE *f, struct rtattr *arg) { SPRINT_BUF(b1); SPRINT_BUF(b2); struct tc_police *p; struct rtattr *tb[TCA_POLICE_MAX+1]; - unsigned buffer; + unsigned int buffer; unsigned int linklayer; if (arg == NULL) @@ -350,25 +287,43 @@ print_police(struct action_util *a, FILE *f, struct rtattr *arg) fprintf(f, "mtu %s ", sprint_size(p->mtu, b1)); if (show_raw) fprintf(f, "[%08x] ", p->burst); + if (p->peakrate.rate) fprintf(f, "peakrate %s ", sprint_rate(p->peakrate.rate, b1)); + if (tb[TCA_POLICE_AVRATE]) - fprintf(f, "avrate %s ", sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]), b1)); - fprintf(f, "action %s", police_action_n2a(p->action, b1, sizeof(b1))); + fprintf(f, "avrate %s ", + sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]), + b1)); + + print_action_control(f, "action ", p->action, ""); + if (tb[TCA_POLICE_RESULT]) { - fprintf(f, "/%s ", police_action_n2a(*(int*)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); + __u32 action = rta_getattr_u32(tb[TCA_POLICE_RESULT]); + + print_action_control(f, "/", action, " "); } else fprintf(f, " "); + fprintf(f, "overhead %ub ", p->rate.overhead); linklayer = (p->rate.linklayer & TC_LINKLAYER_MASK); if (linklayer > TC_LINKLAYER_ETHERNET || show_details) fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b2)); - fprintf(f, "\nref %d bind %d\n",p->refcnt, p->bindcnt); + fprintf(f, "\n\tref %d bind %d", p->refcnt, p->bindcnt); + if (show_stats) { + if (tb[TCA_POLICE_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_POLICE_TM]); + + print_tm(f, tm); + } + } + fprintf(f, "\n"); + return 0; } -int -tc_print_police(FILE *f, struct rtattr *arg) { - return print_police(&police_action_util,f,arg); +int tc_print_police(FILE *f, struct rtattr *arg) +{ + return print_police(&police_action_util, f, arg); } diff --git a/tc/m_sample.c b/tc/m_sample.c new file mode 100644 index 00000000..ff5ee6bd --- /dev/null +++ b/tc/m_sample.c @@ -0,0 +1,184 @@ +/* + * m_sample.c ingress/egress packet sampling module + * + * This program is free software; you can distribute 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: Yotam Gigi <yotamg@mellanox.com> + * + */ + +#include <stdio.h> +#include "utils.h" +#include "tc_util.h" +#include "tc_common.h" +#include <linux/tc_act/tc_sample.h> + +static void explain(void) +{ + fprintf(stderr, "Usage: sample SAMPLE_CONF\n"); + fprintf(stderr, "where:\n"); + fprintf(stderr, "\tSAMPLE_CONF := SAMPLE_PARAMS | SAMPLE_INDEX\n"); + fprintf(stderr, "\tSAMPLE_PARAMS := rate RATE group GROUP [trunc SIZE] [SAMPLE_INDEX]\n"); + fprintf(stderr, "\tSAMPLE_INDEX := index INDEX\n"); + fprintf(stderr, "\tRATE := The ratio of packets observed at the data source to the samples generated.\n"); + fprintf(stderr, "\tGROUP := the psample sampling group\n"); + fprintf(stderr, "\tSIZE := the truncation size\n"); + fprintf(stderr, "\tINDEX := integer index of the sample action\n"); +} + +static void usage(void) +{ + explain(); + exit(-1); +} + +static int parse_sample(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) +{ + struct tc_sample p = { 0 }; + bool trunc_set = false; + bool group_set = false; + bool rate_set = false; + char **argv = *argv_p; + struct rtattr *tail; + int argc = *argc_p; + __u32 trunc; + __u32 group; + __u32 rate; + + if (argc <= 1) { + fprintf(stderr, "sample bad argument count %d\n", argc); + usage(); + return -1; + } + + if (matches(*argv, "sample") == 0) { + NEXT_ARG(); + } else { + fprintf(stderr, "sample bad argument %s\n", *argv); + return -1; + } + + while (argc > 0) { + if (matches(*argv, "rate") == 0) { + NEXT_ARG(); + if (get_unsigned(&rate, *argv, 10) != 0) { + fprintf(stderr, "Illegal rate %s\n", *argv); + usage(); + return -1; + } + rate_set = true; + } else if (matches(*argv, "group") == 0) { + NEXT_ARG(); + if (get_unsigned(&group, *argv, 10) != 0) { + fprintf(stderr, "Illegal group num %s\n", + *argv); + usage(); + return -1; + } + group_set = true; + } else if (matches(*argv, "trunc") == 0) { + NEXT_ARG(); + if (get_unsigned(&trunc, *argv, 10) != 0) { + fprintf(stderr, "Illegal truncation size %s\n", + *argv); + usage(); + return -1; + } + trunc_set = true; + } else if (matches(*argv, "help") == 0) { + usage(); + } else { + break; + } + + NEXT_ARG_FWD(); + } + + parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE); + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&p.index, *argv, 10)) { + fprintf(stderr, "sample: Illegal \"index\"\n"); + return -1; + } + NEXT_ARG_FWD(); + } + } + + if (!p.index && !group_set) { + fprintf(stderr, "param \"group\" not set\n"); + usage(); + } + + if (!p.index && !rate_set) { + fprintf(stderr, "param \"rate\" not set\n"); + usage(); + } + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_SAMPLE_PARMS, &p, sizeof(p)); + if (rate_set) + addattr32(n, MAX_MSG, TCA_SAMPLE_RATE, rate); + if (group_set) + addattr32(n, MAX_MSG, TCA_SAMPLE_PSAMPLE_GROUP, group); + if (trunc_set) + addattr32(n, MAX_MSG, TCA_SAMPLE_TRUNC_SIZE, trunc); + + tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int print_sample(struct action_util *au, FILE *f, struct rtattr *arg) +{ + struct rtattr *tb[TCA_SAMPLE_MAX + 1]; + struct tc_sample *p; + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_SAMPLE_MAX, arg); + + if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] || + !tb[TCA_SAMPLE_PSAMPLE_GROUP]) { + fprintf(f, "[NULL sample parameters]"); + return -1; + } + p = RTA_DATA(tb[TCA_SAMPLE_PARMS]); + + fprintf(f, "sample rate 1/%d group %d", + rta_getattr_u32(tb[TCA_SAMPLE_RATE]), + rta_getattr_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP])); + + if (tb[TCA_SAMPLE_TRUNC_SIZE]) + fprintf(f, " trunc_size %d", + rta_getattr_u32(tb[TCA_SAMPLE_TRUNC_SIZE])); + + fprintf(f, "\n\tindex %d ref %d bind %d", p->index, p->refcnt, + p->bindcnt); + + if (show_stats) { + if (tb[TCA_SAMPLE_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_SAMPLE_TM]); + + print_tm(f, tm); + } + } + fprintf(f, "\n"); + return 0; +} + +struct action_util sample_action_util = { + .id = "sample", + .parse_aopt = parse_sample, + .print_aopt = print_sample, +}; diff --git a/tc/m_simple.c b/tc/m_simple.c index 1ad55268..f8937bca 100644 --- a/tc/m_simple.c +++ b/tc/m_simple.c @@ -81,9 +81,10 @@ #endif static void explain(void) { - fprintf(stderr, "Usage: ... simple STRING\n" - "STRING being an arbitrary string\n" - "example: \"simple blah\"\n"); + fprintf(stderr, "Usage:... simple [sdata STRING] [index INDEX] [CONTROL]\n"); + fprintf(stderr, "\tSTRING being an arbitrary string\n" + "\tINDEX := optional index value used\n" + "\tCONTROL := reclassify|pipe|drop|continue|ok\n"); } static void usage(void) @@ -103,42 +104,43 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct rtattr *tail; char *simpdata = NULL; - while (argc > 0) { if (matches(*argv, "simple") == 0) { NEXT_ARG(); + } else if (matches(*argv, "sdata") == 0) { + NEXT_ARG(); + ok += 1; simpdata = *argv; - ok = 1; argc--; argv++; - break; } else if (matches(*argv, "help") == 0) { usage(); } else { break; } - - } - - if (!ok) { - explain(); - return -1; } if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.index, *argv, 10)) { - fprintf(stderr, "simple: Illegal \"index\"\n"); + fprintf(stderr, "simple: Illegal \"index\" (%s)\n", + *argv); return -1; } + ok += 1; argc--; argv++; } } - if (strlen(simpdata) > (SIMP_MAX_DATA - 1)) { - fprintf(stderr, "simple: Illegal string len %zu <%s> \n", + if (!ok) { + explain(); + return -1; + } + + if (simpdata && (strlen(simpdata) > (SIMP_MAX_DATA - 1))) { + fprintf(stderr, "simple: Illegal string len %zu <%s>\n", strlen(simpdata), simpdata); return -1; } @@ -148,7 +150,8 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel)); - addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); + if (simpdata) + addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc; @@ -156,7 +159,7 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, return 0; } -static int print_simple(struct action_util *au, FILE * f, struct rtattr *arg) +static int print_simple(struct action_util *au, FILE *f, struct rtattr *arg) { struct tc_defact *sel; struct rtattr *tb[TCA_DEF_MAX + 1]; @@ -181,12 +184,13 @@ static int print_simple(struct action_util *au, FILE * f, struct rtattr *arg) simpdata = RTA_DATA(tb[TCA_DEF_DATA]); fprintf(f, "Simple <%s>\n", simpdata); - fprintf(f, "\t index %d ref %d bind %d", sel->index, + fprintf(f, "\t index %u ref %d bind %d", sel->index, sel->refcnt, sel->bindcnt); if (show_stats) { if (tb[TCA_DEF_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_DEF_TM]); + print_tm(f, tm); } } diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c index 36323a9d..aa374fcb 100644 --- a/tc/m_skbedit.c +++ b/tc/m_skbedit.c @@ -26,14 +26,17 @@ #include "utils.h" #include "tc_util.h" #include <linux/tc_act/tc_skbedit.h> +#include <linux/if_packet.h> -static void -explain(void) +static void explain(void) { - fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM]>\n" + fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM] [PT]>\n" "QM = queue_mapping QUEUE_MAPPING\n" - "PM = priority PRIORITY \n" - "MM = mark MARK \n" + "PM = priority PRIORITY\n" + "MM = mark MARK\n" + "PT = ptype PACKETYPE\n" + "PACKETYPE = is one of:\n" + " host, otherhost, broadcast, multicast\n" "QUEUE_MAPPING = device transmit queue to use\n" "PRIORITY = classID to assign to priority field\n" "MARK = firewall mark to set\n"); @@ -55,7 +58,7 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, int ok = 0; struct rtattr *tail; unsigned int tmp; - __u16 queue_mapping; + __u16 queue_mapping, ptype; __u32 flags = 0, priority, mark; struct tc_skbedit sel = { 0 }; @@ -90,6 +93,24 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, return -1; } ok++; + } else if (matches(*argv, "ptype") == 0) { + + NEXT_ARG(); + if (matches(*argv, "host") == 0) { + ptype = PACKET_HOST; + } else if (matches(*argv, "broadcast") == 0) { + ptype = PACKET_BROADCAST; + } else if (matches(*argv, "multicast") == 0) { + ptype = PACKET_MULTICAST; + } else if (matches(*argv, "otherhost") == 0) { + ptype = PACKET_OTHERHOST; + } else { + fprintf(stderr, "Illegal ptype (%s)\n", + *argv); + return -1; + } + flags |= SKBEDIT_F_PTYPE; + ok++; } else if (matches(*argv, "help") == 0) { usage(); } else { @@ -99,26 +120,8 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, argv++; } - sel.action = TC_ACT_PIPE; - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - NEXT_ARG(); - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - NEXT_ARG(); - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - NEXT_ARG(); - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { - sel.action = TC_ACT_OK; - NEXT_ARG(); - } - } + parse_action_control_dflt(&argc, &argv, &sel.action, + false, TC_ACT_PIPE); if (argc) { if (matches(*argv, "index") == 0) { @@ -151,6 +154,9 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, if (flags & SKBEDIT_F_MARK) addattr_l(n, MAX_MSG, TCA_SKBEDIT_MARK, &mark, sizeof(mark)); + if (flags & SKBEDIT_F_PTYPE) + addattr_l(n, MAX_MSG, TCA_SKBEDIT_PTYPE, + &ptype, sizeof(ptype)); tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc; @@ -161,10 +167,11 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg) { struct rtattr *tb[TCA_SKBEDIT_MAX + 1]; + SPRINT_BUF(b1); __u32 *priority; __u32 *mark; - __u16 *queue_mapping; + __u16 *queue_mapping, *ptype; struct tc_skbedit *p = NULL; if (arg == NULL) @@ -192,12 +199,29 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg) mark = RTA_DATA(tb[TCA_SKBEDIT_MARK]); fprintf(f, " mark %d", *mark); } + if (tb[TCA_SKBEDIT_PTYPE] != NULL) { + ptype = RTA_DATA(tb[TCA_SKBEDIT_PTYPE]); + if (*ptype == PACKET_HOST) + fprintf(f, " ptype host"); + else if (*ptype == PACKET_BROADCAST) + fprintf(f, " ptype broadcast"); + else if (*ptype == PACKET_MULTICAST) + fprintf(f, " ptype multicast"); + else if (*ptype == PACKET_OTHERHOST) + fprintf(f, " ptype otherhost"); + else + fprintf(f, " ptype %d", *ptype); + } - fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, p->bindcnt); + print_action_control(f, " ", p->action, ""); + + fprintf(f, "\n\t index %u ref %d bind %d", + p->index, p->refcnt, p->bindcnt); if (show_stats) { if (tb[TCA_SKBEDIT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_SKBEDIT_TM]); + print_tm(f, tm); } } diff --git a/tc/m_skbmod.c b/tc/m_skbmod.c new file mode 100644 index 00000000..ba79308b --- /dev/null +++ b/tc/m_skbmod.c @@ -0,0 +1,236 @@ +/* + * m_skbmod.c skb modifier action module + * + * This program is free software; you can distribute 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: J Hadi Salim (jhs@mojatatu.com) + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <linux/netdevice.h> + +#include "rt_names.h" +#include "utils.h" +#include "tc_util.h" +#include <linux/tc_act/tc_skbmod.h> + +static void skbmod_explain(void) +{ + fprintf(stderr, + "Usage:... skbmod {[set <SETTABLE>] [swap <SWAPABLE>]} [CONTROL] [index INDEX]\n" + "where SETTABLE is: [dmac DMAC] [smac SMAC] [etype ETYPE]\n" + "where SWAPABLE is: \"mac\" to swap mac addresses\n" + "note: \"swap mac\" is done after any outstanding D/SMAC change\n" + "\tDMAC := 6 byte Destination MAC address\n" + "\tSMAC := optional 6 byte Source MAC address\n" + "\tETYPE := optional 16 bit ethertype\n" + "\tCONTROL := reclassify | pipe | drop | continue | ok |\n" + "\t goto chain <CHAIN_INDEX>\n" + "\tINDEX := skbmod index value to use\n"); +} + +static void skbmod_usage(void) +{ + skbmod_explain(); + exit(-1); +} + +static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) +{ + int argc = *argc_p; + char **argv = *argv_p; + int ok = 0; + struct tc_skbmod p; + struct rtattr *tail; + char dbuf[ETH_ALEN]; + char sbuf[ETH_ALEN]; + __u16 skbmod_etype = 0; + char *daddr = NULL; + char *saddr = NULL; + + memset(&p, 0, sizeof(p)); + + if (argc <= 0) + return -1; + + while (argc > 0) { + if (matches(*argv, "skbmod") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "swap") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "mac") == 0) { + p.flags |= SKBMOD_F_SWAPMAC; + ok += 1; + } else if (matches(*argv, "set") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "etype") == 0) { + NEXT_ARG(); + if (get_u16(&skbmod_etype, *argv, 0)) + invarg("ethertype is invalid", *argv); + fprintf(stderr, "skbmod etype 0x%x\n", skbmod_etype); + p.flags |= SKBMOD_F_ETYPE; + ok += 1; + } else if (matches(*argv, "dmac") == 0) { + NEXT_ARG(); + daddr = *argv; + if (sscanf(daddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + dbuf, dbuf + 1, dbuf + 2, + dbuf + 3, dbuf + 4, dbuf + 5) != 6) { + fprintf(stderr, "Invalid dst mac address %s\n", + daddr); + return -1; + } + p.flags |= SKBMOD_F_DMAC; + fprintf(stderr, "dst MAC address <%s>\n", daddr); + ok += 1; + + } else if (matches(*argv, "smac") == 0) { + NEXT_ARG(); + saddr = *argv; + if (sscanf(saddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + sbuf, sbuf + 1, sbuf + 2, + sbuf + 3, sbuf + 4, sbuf + 5) != 6) { + fprintf(stderr, "Invalid smac address %s\n", + saddr); + return -1; + } + p.flags |= SKBMOD_F_SMAC; + fprintf(stderr, "src MAC address <%s>\n", saddr); + ok += 1; + } else if (matches(*argv, "help") == 0) { + skbmod_usage(); + } else { + break; + } + + argc--; + argv++; + } + + parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE); + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&p.index, *argv, 0)) { + fprintf(stderr, "skbmod: Illegal \"index\"\n"); + return -1; + } + ok++; + argc--; + argv++; + } + } + + if (!ok) { + fprintf(stderr, "skbmod requires at least one option\n"); + skbmod_usage(); + } + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_SKBMOD_PARMS, &p, sizeof(p)); + + if (daddr) + addattr_l(n, MAX_MSG, TCA_SKBMOD_DMAC, dbuf, ETH_ALEN); + if (skbmod_etype) + addattr16(n, MAX_MSG, TCA_SKBMOD_ETYPE, skbmod_etype); + if (saddr) + addattr_l(n, MAX_MSG, TCA_SKBMOD_SMAC, sbuf, ETH_ALEN); + + tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int print_skbmod(struct action_util *au, FILE *f, struct rtattr *arg) +{ + struct tc_skbmod *p = NULL; + struct rtattr *tb[TCA_SKBMOD_MAX + 1]; + __u16 skbmod_etype = 0; + int has_optional = 0; + SPRINT_BUF(b1); + SPRINT_BUF(b2); + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_SKBMOD_MAX, arg); + + if (tb[TCA_SKBMOD_PARMS] == NULL) { + fprintf(f, "[NULL skbmod parameters]"); + return -1; + } + + p = RTA_DATA(tb[TCA_SKBMOD_PARMS]); + + fprintf(f, "skbmod "); + print_action_control(f, "", p->action, " "); + + if (tb[TCA_SKBMOD_ETYPE]) { + skbmod_etype = rta_getattr_u16(tb[TCA_SKBMOD_ETYPE]); + has_optional = 1; + fprintf(f, "set etype 0x%X ", skbmod_etype); + } + + if (has_optional) + fprintf(f, "\n\t "); + + if (tb[TCA_SKBMOD_DMAC]) { + has_optional = 1; + fprintf(f, "set dmac %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_SKBMOD_DMAC]), + RTA_PAYLOAD(tb[TCA_SKBMOD_DMAC]), 0, b1, + sizeof(b1))); + + } + + if (tb[TCA_SKBMOD_SMAC]) { + has_optional = 1; + fprintf(f, "set smac %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_SKBMOD_SMAC]), + RTA_PAYLOAD(tb[TCA_SKBMOD_SMAC]), 0, b2, + sizeof(b2))); + } + + if (p->flags & SKBMOD_F_SWAPMAC) + fprintf(f, "swap mac "); + + fprintf(f, "\n\t index %u ref %d bind %d", p->index, p->refcnt, + p->bindcnt); + if (show_stats) { + if (tb[TCA_SKBMOD_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_SKBMOD_TM]); + + print_tm(f, tm); + } + } + + fprintf(f, "\n"); + + return 0; +} + +struct action_util skbmod_action_util = { + .id = "skbmod", + .parse_aopt = parse_skbmod, + .print_aopt = print_skbmod, +}; diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c new file mode 100644 index 00000000..1cdd0356 --- /dev/null +++ b/tc/m_tunnel_key.c @@ -0,0 +1,315 @@ +/* + * m_tunnel_key.c ip tunnel manipulation module + * + * 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: Amir Vadai <amir@vadai.me> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <linux/if_ether.h> +#include "utils.h" +#include "rt_names.h" +#include "tc_util.h" +#include <linux/tc_act/tc_tunnel_key.h> + +static void explain(void) +{ + fprintf(stderr, "Usage: tunnel_key unset\n"); + fprintf(stderr, " tunnel_key set <TUNNEL_KEY>\n"); + fprintf(stderr, + "Where TUNNEL_KEY is a combination of:\n" + "id <TUNNELID> (mandatory)\n" + "src_ip <IP> (mandatory)\n" + "dst_ip <IP> (mandatory)\n" + "dst_port <UDP_PORT>\n" + "csum | nocsum (default is \"csum\")\n"); +} + +static void usage(void) +{ + explain(); + exit(-1); +} + +static int tunnel_key_parse_ip_addr(const char *str, int addr4_type, + int addr6_type, struct nlmsghdr *n) +{ + inet_prefix addr; + int ret; + + ret = get_addr(&addr, str, AF_UNSPEC); + if (ret) + return ret; + + addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type, + addr.data, addr.bytelen); + + return 0; +} + +static int tunnel_key_parse_key_id(const char *str, int type, + struct nlmsghdr *n) +{ + __be32 key_id; + int ret; + + ret = get_be32(&key_id, str, 10); + if (!ret) + addattr32(n, MAX_MSG, type, key_id); + + return ret; +} + +static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n) +{ + int ret; + __be16 dst_port; + + ret = get_be16(&dst_port, str, 10); + if (ret) + return -1; + + addattr16(n, MAX_MSG, type, dst_port); + + return 0; +} + +static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) +{ + struct tc_tunnel_key parm = {}; + char **argv = *argv_p; + int argc = *argc_p; + struct rtattr *tail; + int action = 0; + int ret; + int has_src_ip = 0; + int has_dst_ip = 0; + int has_key_id = 0; + int csum = 1; + + if (matches(*argv, "tunnel_key") != 0) + return -1; + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + + NEXT_ARG(); + + while (argc > 0) { + if (matches(*argv, "unset") == 0) { + if (action) { + fprintf(stderr, "unexpected \"%s\" - action already specified\n", + *argv); + explain(); + return -1; + } + action = TCA_TUNNEL_KEY_ACT_RELEASE; + } else if (matches(*argv, "set") == 0) { + if (action) { + fprintf(stderr, "unexpected \"%s\" - action already specified\n", + *argv); + explain(); + return -1; + } + action = TCA_TUNNEL_KEY_ACT_SET; + } else if (matches(*argv, "src_ip") == 0) { + NEXT_ARG(); + ret = tunnel_key_parse_ip_addr(*argv, + TCA_TUNNEL_KEY_ENC_IPV4_SRC, + TCA_TUNNEL_KEY_ENC_IPV6_SRC, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"src_ip\"\n"); + return -1; + } + has_src_ip = 1; + } else if (matches(*argv, "dst_ip") == 0) { + NEXT_ARG(); + ret = tunnel_key_parse_ip_addr(*argv, + TCA_TUNNEL_KEY_ENC_IPV4_DST, + TCA_TUNNEL_KEY_ENC_IPV6_DST, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"dst_ip\"\n"); + return -1; + } + has_dst_ip = 1; + } else if (matches(*argv, "id") == 0) { + NEXT_ARG(); + ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"id\"\n"); + return -1; + } + has_key_id = 1; + } else if (matches(*argv, "dst_port") == 0) { + NEXT_ARG(); + ret = tunnel_key_parse_dst_port(*argv, + TCA_TUNNEL_KEY_ENC_DST_PORT, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"dst port\"\n"); + return -1; + } + } else if (matches(*argv, "csum") == 0) { + csum = 1; + } else if (matches(*argv, "nocsum") == 0) { + csum = 0; + } else if (matches(*argv, "help") == 0) { + usage(); + } else { + break; + } + NEXT_ARG_FWD(); + } + + addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum); + + parse_action_control_dflt(&argc, &argv, &parm.action, + false, TC_ACT_PIPE); + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&parm.index, *argv, 10)) { + fprintf(stderr, "tunnel_key: Illegal \"index\"\n"); + return -1; + } + + NEXT_ARG_FWD(); + } + } + + if (action == TCA_TUNNEL_KEY_ACT_SET && + (!has_src_ip || !has_dst_ip || !has_key_id)) { + fprintf(stderr, "set needs tunnel_key parameters\n"); + explain(); + return -1; + } + + parm.t_action = action; + addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm)); + tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; + + *argc_p = argc; + *argv_p = argv; + + return 0; +} + +static void tunnel_key_print_ip_addr(FILE *f, const char *name, + struct rtattr *attr) +{ + int family; + size_t len; + + if (!attr) + return; + + len = RTA_PAYLOAD(attr); + + if (len == 4) + family = AF_INET; + else if (len == 16) + family = AF_INET6; + else + return; + + fprintf(f, "\n\t%s %s", name, rt_addr_n2a_rta(family, attr)); +} + +static void tunnel_key_print_key_id(FILE *f, const char *name, + struct rtattr *attr) +{ + if (!attr) + return; + fprintf(f, "\n\t%s %d", name, rta_getattr_be32(attr)); +} + +static void tunnel_key_print_dst_port(FILE *f, char *name, + struct rtattr *attr) +{ + if (!attr) + return; + fprintf(f, "\n\t%s %d", name, rta_getattr_be16(attr)); +} + +static void tunnel_key_print_flag(FILE *f, const char *name_on, + const char *name_off, + struct rtattr *attr) +{ + if (!attr) + return; + fprintf(f, "\n\t%s", rta_getattr_u8(attr) ? name_on : name_off); +} + +static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg) +{ + struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1]; + struct tc_tunnel_key *parm; + + if (!arg) + return -1; + + parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg); + + if (!tb[TCA_TUNNEL_KEY_PARMS]) { + fprintf(f, "[NULL tunnel_key parameters]"); + return -1; + } + parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]); + + fprintf(f, "tunnel_key"); + + switch (parm->t_action) { + case TCA_TUNNEL_KEY_ACT_RELEASE: + fprintf(f, " unset"); + break; + case TCA_TUNNEL_KEY_ACT_SET: + fprintf(f, " set"); + tunnel_key_print_ip_addr(f, "src_ip", + tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]); + tunnel_key_print_ip_addr(f, "dst_ip", + tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]); + tunnel_key_print_ip_addr(f, "src_ip", + tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]); + tunnel_key_print_ip_addr(f, "dst_ip", + tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]); + tunnel_key_print_key_id(f, "key_id", + tb[TCA_TUNNEL_KEY_ENC_KEY_ID]); + tunnel_key_print_dst_port(f, "dst_port", + tb[TCA_TUNNEL_KEY_ENC_DST_PORT]); + tunnel_key_print_flag(f, "nocsum", "csum", + tb[TCA_TUNNEL_KEY_NO_CSUM]); + break; + } + print_action_control(f, " ", parm->action, ""); + + fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt, + parm->bindcnt); + + if (show_stats) { + if (tb[TCA_TUNNEL_KEY_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]); + + print_tm(f, tm); + } + } + + fprintf(f, "\n "); + + return 0; +} + +struct action_util tunnel_key_action_util = { + .id = "tunnel_key", + .parse_aopt = parse_tunnel_key, + .print_aopt = print_tunnel_key, +}; diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 32db5ed5..cccb4996 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -19,12 +19,21 @@ #include "tc_util.h" #include <linux/tc_act/tc_vlan.h> +static const char * const action_names[] = { + [TCA_VLAN_ACT_POP] = "pop", + [TCA_VLAN_ACT_PUSH] = "push", + [TCA_VLAN_ACT_MODIFY] = "modify", +}; + static void explain(void) { fprintf(stderr, "Usage: vlan pop\n"); - fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID\n"); + fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"); + fprintf(stderr, " vlan modify [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"); fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n"); fprintf(stderr, " with default: 802.1Q\n"); + fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass |\n"); + fprintf(stderr, " goto chain <CHAIN_INDEX>\n"); } static void usage(void) @@ -33,6 +42,11 @@ static void usage(void) exit(-1); } +static bool has_push_attribs(int action) +{ + return action == TCA_VLAN_ACT_PUSH || action == TCA_VLAN_ACT_MODIFY; +} + static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { @@ -44,7 +58,9 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, int id_set = 0; __u16 proto; int proto_set = 0; - struct tc_vlan parm = { 0 }; + __u8 prio; + int prio_set = 0; + struct tc_vlan parm = {}; if (matches(*argv, "vlan") != 0) return -1; @@ -68,9 +84,17 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, return -1; } action = TCA_VLAN_ACT_PUSH; + } else if (matches(*argv, "modify") == 0) { + if (action) { + fprintf(stderr, "unexpected \"%s\" - action already specified\n", + *argv); + explain(); + return -1; + } + action = TCA_VLAN_ACT_MODIFY; } else if (matches(*argv, "id") == 0) { - if (action != TCA_VLAN_ACT_PUSH) { - fprintf(stderr, "\"%s\" is only valid for push\n", + if (!has_push_attribs(action)) { + fprintf(stderr, "\"%s\" is only valid for push/modify\n", *argv); explain(); return -1; @@ -80,8 +104,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, invarg("id is invalid", *argv); id_set = 1; } else if (matches(*argv, "protocol") == 0) { - if (action != TCA_VLAN_ACT_PUSH) { - fprintf(stderr, "\"%s\" is only valid for push\n", + if (!has_push_attribs(action)) { + fprintf(stderr, "\"%s\" is only valid for push/modify\n", *argv); explain(); return -1; @@ -90,6 +114,17 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, if (ll_proto_a2n(&proto, *argv)) invarg("protocol is invalid", *argv); proto_set = 1; + } else if (matches(*argv, "priority") == 0) { + if (!has_push_attribs(action)) { + fprintf(stderr, "\"%s\" is only valid for push/modify\n", + *argv); + explain(); + return -1; + } + NEXT_ARG(); + if (get_u8(&prio, *argv, 0) || (prio & ~0x7)) + invarg("prio is invalid", *argv); + prio_set = 1; } else if (matches(*argv, "help") == 0) { usage(); } else { @@ -99,31 +134,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, argv++; } - parm.action = TC_ACT_PIPE; - if (argc) { - if (matches(*argv, "reclassify") == 0) { - parm.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - parm.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - parm.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - parm.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0) { - parm.action = TC_ACT_OK; - argc--; - argv++; - } - } + parse_action_control_dflt(&argc, &argv, &parm.action, + false, TC_ACT_PIPE); if (argc) { if (matches(*argv, "index") == 0) { @@ -137,8 +149,9 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, } } - if (action == TCA_VLAN_ACT_PUSH && !id_set) { - fprintf(stderr, "id needs to be set for push\n"); + if (has_push_attribs(action) && !id_set) { + fprintf(stderr, "id needs to be set for %s\n", + action_names[action]); explain(); return -1; } @@ -159,6 +172,9 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PROTOCOL, &proto, 2); } + if (prio_set) + addattr8(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PRIORITY, prio); + tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc; @@ -186,12 +202,13 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) fprintf(f, " vlan"); - switch(parm->v_action) { + switch (parm->v_action) { case TCA_VLAN_ACT_POP: fprintf(f, " pop"); break; case TCA_VLAN_ACT_PUSH: - fprintf(f, " push"); + case TCA_VLAN_ACT_MODIFY: + fprintf(f, " %s", action_names[parm->v_action]); if (tb[TCA_VLAN_PUSH_VLAN_ID]) { val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); fprintf(f, " id %u", val); @@ -201,16 +218,21 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]), b1, sizeof(b1))); } + if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) { + val = rta_getattr_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]); + fprintf(f, " priority %u", val); + } break; } - fprintf(f, " %s", action_n2a(parm->action, b1, sizeof (b1))); + print_action_control(f, " ", parm->action, ""); - fprintf(f, "\n\t index %d ref %d bind %d", parm->index, parm->refcnt, + fprintf(f, "\n\t index %u ref %d bind %d", parm->index, parm->refcnt, parm->bindcnt); if (show_stats) { if (tb[TCA_VLAN_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_VLAN_TM]); + print_tm(f, tm); } } @@ -39,19 +39,21 @@ #endif #ifndef __ALIGN_KERNEL -#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) -#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define __ALIGN_KERNEL(x, a) \ + __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_KERNEL_MASK(x, mask) \ + (((x) + (mask)) & ~(mask)) #endif #ifndef ALIGN -#define ALIGN(x,a) __ALIGN_KERNEL((x), (a)) +#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) #endif static const char *tname = "mangle"; char *lib_dir; -static const char *ipthooks[] = { +static const char * const ipthooks[] = { "NF_IP_PRE_ROUTING", "NF_IP_LOCAL_IN", "NF_IP_FORWARD", @@ -75,6 +77,9 @@ static struct xtables_globals tcipt_globals = { .orig_opts = original_opts, .opts = original_opts, .exit_err = NULL, +#if XTABLES_VERSION_CODE >= 11 + .compat_rev = xtables_compatible_revision, +#endif }; /* @@ -85,12 +90,13 @@ build_st(struct xtables_target *target, struct xt_entry_target *t) { size_t size = - XT_ALIGN(sizeof (struct xt_entry_target)) + target->size; + XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; - if (NULL == t) { + if (t == NULL) { target->t = xtables_calloc(1, size); target->t->u.target_size = size; - strcpy(target->t->u.user.name, target->name); + strncpy(target->t->u.user.name, target->name, + sizeof(target->t->u.user.name) - 1); target->t->u.user.revision = target->revision; if (target->init != NULL) @@ -109,95 +115,110 @@ static void set_lib_dir(void) if (!lib_dir) { lib_dir = getenv("IPTABLES_LIB_DIR"); if (lib_dir) - fprintf(stderr, "using deprecated IPTABLES_LIB_DIR \n"); + fprintf(stderr, "using deprecated IPTABLES_LIB_DIR\n"); } if (lib_dir == NULL) lib_dir = XT_LIB_DIR; } -static int parse_ipt(struct action_util *a,int *argc_p, +static int get_xtables_target_opts(struct xtables_globals *globals, + struct xtables_target *m) +{ + struct option *opts; + +#if XTABLES_VERSION_CODE >= 6 + opts = xtables_options_xfrm(globals->orig_opts, + globals->opts, + m->x6_options, + &m->option_offset); +#else + opts = xtables_merge_options(globals->opts, + m->extra_opts, + &m->option_offset); +#endif + if (!opts) + return -1; + globals->opts = opts; + return 0; +} + +static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct xtables_target *m = NULL; - struct ipt_entry fw; +#if XTABLES_VERSION_CODE >= 6 + struct ipt_entry fw = {}; +#endif struct rtattr *tail; int c; - int rargc = *argc_p; char **argv = *argv_p; - int argc = 0, iargc = 0; + int argc; char k[16]; int size = 0; int iok = 0, ok = 0; __u32 hook = 0, index = 0; - struct option *opts = NULL; - xtables_init_all(&tcipt_globals, NFPROTO_IPV4); + /* copy tcipt_globals because .opts will be modified by iptables */ + struct xtables_globals tmp_tcipt_globals = tcipt_globals; + + xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4); set_lib_dir(); - { - int i; - for (i = 0; i < rargc; i++) { - if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { - break; - } - } - iargc = argc = i; + /* parse only up until the next action */ + for (argc = 0; argc < *argc_p; argc++) { + if (!argv[argc] || !strcmp(argv[argc], "action")) + break; } if (argc <= 2) { - fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); + fprintf(stderr, + "too few arguments for xt, need at least '-j <target>'\n"); return -1; } while (1) { - c = getopt_long(argc, argv, "j:", tcipt_globals.opts, NULL); + c = getopt_long(argc, argv, "j:", tmp_tcipt_globals.opts, NULL); if (c == -1) break; switch (c) { case 'j': m = xtables_find_target(optarg, XTF_TRY_LOAD); - if (NULL != m) { - - if (0 > build_st(m, NULL)) { - printf(" %s error \n", m->name); - return -1; - } -#if (XTABLES_VERSION_CODE >= 6) - opts = xtables_options_xfrm(tcipt_globals.orig_opts, - tcipt_globals.opts, - m->x6_options, - &m->option_offset); -#else - opts = xtables_merge_options(tcipt_globals.opts, - m->extra_opts, - &m->option_offset); -#endif - if (opts == NULL) { - fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); + if (!m) { + fprintf(stderr, + " failed to find target %s\n\n", + optarg); return -1; - } else - tcipt_globals.opts = opts; - } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + } + + if (build_st(m, NULL) < 0) { + printf(" %s error\n", m->name); + return -1; + } + + if (get_xtables_target_opts(&tmp_tcipt_globals, + m) < 0) { + fprintf(stderr, + " failed to find additional options for target %s\n\n", + optarg); return -1; } ok++; break; default: - memset(&fw, 0, sizeof (fw)); -#if (XTABLES_VERSION_CODE >= 6) - if (m != NULL && m->x6_parse != NULL ) { - xtables_option_tpcall(c, argv, 0 , m, NULL); +#if XTABLES_VERSION_CODE >= 6 + if (m != NULL && m->x6_parse != NULL) { + xtables_option_tpcall(c, argv, 0, m, &fw); #else - if (m != NULL && m->parse != NULL ) { - m->parse(c - m->option_offset, argv, 0, &m->tflags, - NULL, &m->t); + if (m != NULL && m->parse != NULL) { + m->parse(c - m->option_offset, argv, 0, + &m->tflags, NULL, &m->t); #endif } else { - fprintf(stderr,"failed to find target %s\n\n", optarg); + fprintf(stderr, + "failed to find target %s\n\n", optarg); return -1; } @@ -206,7 +227,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } } - if (iargc > optind) { + if (argc > optind) { if (matches(argv[optind], "index") == 0) { if (get_u32(&index, argv[optind + 1], 10)) { fprintf(stderr, "Illegal \"index\"\n"); @@ -220,12 +241,12 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (!ok && !iok) { - fprintf(stderr," ipt Parser BAD!! (%s)\n", *argv); + fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); return -1; } /* check that we passed the correct parameters to the target */ -#if (XTABLES_VERSION_CODE >= 6) +#if XTABLES_VERSION_CODE >= 6 if (m) xtables_option_tfcall(m); #else @@ -235,6 +256,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { struct tcmsg *t = NLMSG_DATA(n); + if (t->tcm_parent != TC_H_ROOT && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { hook = NF_IP_PRE_ROUTING; @@ -248,12 +270,16 @@ static int parse_ipt(struct action_util *a,int *argc_p, fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]); fprintf(stdout, "\ttarget: "); - if (m) - m->print(NULL, m->t, 0); + if (m) { + if (m->print) + m->print(NULL, m->t, 0); + else + printf("%s ", m->name); + } fprintf(stdout, " index %d\n", index); - if (strlen(tname) > 16) { - size = 16; + if (strlen(tname) >= 16) { + size = 15; k[15] = 0; } else { size = 1 + strlen(tname); @@ -267,9 +293,8 @@ static int parse_ipt(struct action_util *a,int *argc_p, addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; - argc -= optind; argv += optind; - *argc_p = rargc - iargc; + *argc_p -= argc; *argv_p = argv; optind = 0; @@ -289,11 +314,11 @@ static int parse_ipt(struct action_util *a,int *argc_p, } static int -print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) +print_ipt(struct action_util *au, FILE *f, struct rtattr *arg) { + struct xtables_target *m; struct rtattr *tb[TCA_IPT_MAX + 1]; struct xt_entry_target *t = NULL; - struct option *opts = NULL; if (arg == NULL) return -1; @@ -318,73 +343,66 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) return -1; } else { __u32 hook; + hook = rta_getattr_u32(tb[TCA_IPT_HOOK]); - fprintf(f, " hook: %s \n", ipthooks[hook]); + fprintf(f, " hook: %s\n", ipthooks[hook]); } if (tb[TCA_IPT_TARG] == NULL) { - fprintf(f, "\t[NULL ipt target parameters ] \n"); + fprintf(f, "\t[NULL ipt target parameters ]\n"); return -1; - } else { - struct xtables_target *m = NULL; - t = RTA_DATA(tb[TCA_IPT_TARG]); - m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD); - if (NULL != m) { - if (0 > build_st(m, t)) { - fprintf(stderr, " %s error \n", m->name); - return -1; - } + } -#if (XTABLES_VERSION_CODE >= 6) - opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, - tmp_tcipt_globals.opts, - m->x6_options, - &m->option_offset); -#else - opts = xtables_merge_options(tmp_tcipt_globals.opts, - m->extra_opts, - &m->option_offset); -#endif - if (opts == NULL) { - fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); + t = RTA_DATA(tb[TCA_IPT_TARG]); + m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD); + if (!m) { + fprintf(stderr, " failed to find target %s\n\n", + t->u.user.name); return -1; - } else - tmp_tcipt_globals.opts = opts; - } else { - fprintf(stderr, " failed to find target %s\n\n", - t->u.user.name); - return -1; - } - fprintf(f, "\ttarget "); - m->print(NULL, m->t, 0); - if (tb[TCA_IPT_INDEX] == NULL) { - fprintf(f, " [NULL ipt target index ]\n"); - } else { - __u32 index; - index = rta_getattr_u32(tb[TCA_IPT_INDEX]); - fprintf(f, " \n\tindex %d", index); - } + } + if (build_st(m, t) < 0) { + fprintf(stderr, " %s error\n", m->name); + return -1; + } - if (tb[TCA_IPT_CNT]) { - struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);; - fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); - } - if (show_stats) { - if (tb[TCA_IPT_TM]) { - struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); - print_tm(f,tm); - } - } - fprintf(f, " \n"); + if (get_xtables_target_opts(&tmp_tcipt_globals, m) < 0) { + fprintf(stderr, + " failed to find additional options for target %s\n\n", + t->u.user.name); + return -1; + } + fprintf(f, "\ttarget "); + m->print(NULL, m->t, 0); + if (tb[TCA_IPT_INDEX] == NULL) { + fprintf(f, " [NULL ipt target index ]\n"); + } else { + __u32 index; + index = rta_getattr_u32(tb[TCA_IPT_INDEX]); + fprintf(f, "\n\tindex %u", index); } + + if (tb[TCA_IPT_CNT]) { + struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); + + fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); + } + if (show_stats) { + if (tb[TCA_IPT_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); + + print_tm(f, tm); + } + } + fprintf(f, "\n"); + xtables_free_opts(1); return 0; } struct action_util xt_action_util = { - .id = "xt", - .parse_aopt = parse_ipt, - .print_aopt = print_ipt, + .id = "xt", + .parse_aopt = parse_ipt, + .print_aopt = print_ipt, }; diff --git a/tc/m_xt_old.c b/tc/m_xt_old.c index 6e643088..e9cc624e 100644 --- a/tc/m_xt_old.c +++ b/tc/m_xt_old.c @@ -41,8 +41,8 @@ #endif #ifndef ALIGN -#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) -#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) +#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) #endif static const char *pname = "tc-ipt"; @@ -63,7 +63,7 @@ static struct option original_opts[] = { }; static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; +static unsigned int global_option_offset; char *lib_dir; const char *program_version = XTABLES_VERSION; const char *program_name = "tc-ipt"; @@ -96,18 +96,18 @@ merge_options(struct option *oldopts, const struct option *newopts, struct option *merge; unsigned int num_old, num_new, i; - for (num_old = 0; oldopts[num_old].name; num_old++) ; - for (num_new = 0; newopts[num_new].name; num_new++) ; + for (num_old = 0; oldopts[num_old].name; num_old++); + for (num_new = 0; newopts[num_new].name; num_new++); *option_offset = global_option_offset + OPTION_OFFSET; - merge = malloc(sizeof (struct option) * (num_new + num_old + 1)); - memcpy(merge, oldopts, num_old * sizeof (struct option)); + merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); + memcpy(merge, oldopts, num_old * sizeof(struct option)); for (i = 0; i < num_new; i++) { merge[num_old + i] = newopts[i]; merge[num_old + i].val += *option_offset; } - memset(merge + num_old + num_new, 0, sizeof (struct option)); + memset(merge + num_old + num_new, 0, sizeof(struct option)); return merge; } @@ -125,35 +125,35 @@ merge_options(struct option *oldopts, const struct option *newopts, int check_inverse(const char option[], int *invert, int *my_optind, int argc) { - if (option && strcmp(option, "!") == 0) { - if (*invert) - exit_error(PARAMETER_PROBLEM, - "Multiple `!' flags not allowed"); - *invert = TRUE; - if (my_optind != NULL) { - ++*my_optind; - if (argc && *my_optind > argc) - exit_error(PARAMETER_PROBLEM, - "no argument following `!'"); - } - - return TRUE; - } - return FALSE; + if (option && strcmp(option, "!") == 0) { + if (*invert) + exit_error(PARAMETER_PROBLEM, + "Multiple `!' flags not allowed"); + *invert = TRUE; + if (my_optind != NULL) { + ++*my_optind; + if (argc && *my_optind > argc) + exit_error(PARAMETER_PROBLEM, + "no argument following `!'"); + } + + return TRUE; + } + return FALSE; } /*XXX: TC_CONFIG_XT_H */ void exit_error(enum exittype status, const char *msg, ...) { - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s: ", pname, pversion); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - /* On error paths, make sure that we don't leak memory */ - exit(status); + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s v%s: ", pname, pversion); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + /* On error paths, make sure that we don't leak memory */ + exit(status); } /*XXX: TC_CONFIG_XT_H */ @@ -173,9 +173,9 @@ build_st(struct xtables_target *target, struct xt_entry_target *t) { size_t size = - XT_ALIGN(sizeof (struct xt_entry_target)) + target->size; + XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; - if (NULL == t) { + if (t == NULL) { target->t = fw_calloc(1, size); target->t->u.target_size = size; strcpy(target->t->u.user.name, target->name); @@ -197,14 +197,14 @@ inline void set_lib_dir(void) if (!lib_dir) { lib_dir = getenv("IPTABLES_LIB_DIR"); if (lib_dir) - fprintf(stderr, "using deprecated IPTABLES_LIB_DIR \n"); + fprintf(stderr, "using deprecated IPTABLES_LIB_DIR\n"); } if (lib_dir == NULL) lib_dir = XT_LIB_DIR; } -static int parse_ipt(struct action_util *a,int *argc_p, +static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct xtables_target *m = NULL; @@ -223,6 +223,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { int i; + for (i = 0; i < rargc; i++) { if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { break; @@ -232,7 +233,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (argc <= 2) { - fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); + fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc); return -1; } @@ -243,29 +244,29 @@ static int parse_ipt(struct action_util *a,int *argc_p, switch (c) { case 'j': m = find_target(optarg, TRY_LOAD); - if (NULL != m) { + if (m != NULL) { - if (0 > build_st(m, NULL)) { - printf(" %s error \n", m->name); + if (build_st(m, NULL) < 0) { + printf(" %s error\n", m->name); return -1; } opts = merge_options(opts, m->extra_opts, &m->option_offset); } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } ok++; break; default: - memset(&fw, 0, sizeof (fw)); + memset(&fw, 0, sizeof(fw)); if (m) { m->parse(c - m->option_offset, argv, 0, &m->tflags, NULL, &m->t); } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } @@ -289,7 +290,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (!ok && !iok) { - fprintf(stderr," ipt Parser BAD!! (%s)\n", *argv); + fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); return -1; } @@ -299,6 +300,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { struct tcmsg *t = NLMSG_DATA(n); + if (t->tcm_parent != TC_H_ROOT && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { hook = NF_IP_PRE_ROUTING; @@ -339,11 +341,11 @@ static int parse_ipt(struct action_util *a,int *argc_p, optind = 0; free_opts(opts); /* Clear flags if target will be used again */ - m->tflags=0; - m->used=0; + m->tflags = 0; + m->used = 0; /* Free allocated memory */ - if (m->t) - free(m->t); + if (m->t) + free(m->t); return 0; @@ -351,7 +353,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } static int -print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) +print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) { struct rtattr *tb[TCA_IPT_MAX + 1]; struct xt_entry_target *t = NULL; @@ -375,20 +377,22 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) return -1; } else { __u32 hook; + hook = rta_getattr_u32(tb[TCA_IPT_HOOK]); - fprintf(f, " hook: %s \n", ipthooks[hook]); + fprintf(f, " hook: %s\n", ipthooks[hook]); } if (tb[TCA_IPT_TARG] == NULL) { - fprintf(f, "\t[NULL ipt target parameters ] \n"); + fprintf(f, "\t[NULL ipt target parameters ]\n"); return -1; } else { struct xtables_target *m = NULL; + t = RTA_DATA(tb[TCA_IPT_TARG]); m = find_target(t->u.user.name, TRY_LOAD); - if (NULL != m) { - if (0 > build_st(m, t)) { - fprintf(stderr, " %s error \n", m->name); + if (m != NULL) { + if (build_st(m, t) < 0) { + fprintf(stderr, " %s error\n", m->name); return -1; } @@ -406,21 +410,24 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) fprintf(f, " [NULL ipt target index ]\n"); } else { __u32 index; + index = rta_getattr_u32(tb[TCA_IPT_INDEX]); - fprintf(f, " \n\tindex %d", index); + fprintf(f, "\n\tindex %u", index); } if (tb[TCA_IPT_CNT]) { - struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);; + struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); + fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); } if (show_stats) { if (tb[TCA_IPT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } - fprintf(f, " \n"); + fprintf(f, "\n"); } free_opts(opts); @@ -429,7 +436,7 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) } struct action_util ipt_action_util = { - .id = "ipt", - .parse_aopt = parse_ipt, - .print_aopt = print_ipt, + .id = "ipt", + .parse_aopt = parse_ipt, + .print_aopt = print_ipt, }; diff --git a/tc/p_eth.c b/tc/p_eth.c new file mode 100644 index 00000000..2d2f96ca --- /dev/null +++ b/tc/p_eth.c @@ -0,0 +1,75 @@ +/* + * m_pedit_eth.c packet editor: ETH header + * + * This program is free software; you can distribute 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: Amir Vadai (amir@vadai.me) + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include "utils.h" +#include "tc_util.h" +#include "m_pedit.h" + +static int +parse_eth(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, struct m_pedit_key *tkey) +{ + int res = -1; + int argc = *argc_p; + char **argv = *argv_p; + + if (argc < 2) + return -1; + + if (!sel->extended) + return -1; + + tkey->htype = TCA_PEDIT_KEY_EX_HDR_TYPE_ETH; + + if (strcmp(*argv, "type") == 0) { + NEXT_ARG(); + tkey->off = 12; + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); + goto done; + } + + if (strcmp(*argv, "dst") == 0) { + NEXT_ARG(); + tkey->off = 0; + res = parse_cmd(&argc, &argv, 6, TMAC, RU32, sel, tkey); + goto done; + } + + if (strcmp(*argv, "src") == 0) { + NEXT_ARG(); + tkey->off = 6; + res = parse_cmd(&argc, &argv, 6, TMAC, RU32, sel, tkey); + goto done; + } + + return -1; + +done: + *argc_p = argc; + *argv_p = argv; + return res; +} + +struct m_pedit_util p_pedit_eth = { + NULL, + "eth", + parse_eth, +}; diff --git a/tc/p_icmp.c b/tc/p_icmp.c index a4b80c2c..1c3a5d90 100644 --- a/tc/p_icmp.c +++ b/tc/p_icmp.c @@ -25,7 +25,8 @@ static int -parse_icmp(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_icmp(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, struct m_pedit_key *tkey) { int res = -1; #if 0 @@ -47,7 +48,7 @@ parse_icmp(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_ } return -1; - done: +done: *argc_p = argc; *argv_p = argv; #endif @@ -1,5 +1,5 @@ /* - * m_pedit.c packet editor: IPV4/6 header + * p_ip.c packet editor: IPV4 header * * This program is free software; you can distribute it and/or * modify it under the terms of the GNU General Public License @@ -24,7 +24,8 @@ #include "m_pedit.h" static int -parse_ip(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_ip(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, struct m_pedit_key *tkey) { int res = -1; int argc = *argc_p; @@ -33,16 +34,20 @@ parse_ip(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_ke if (argc < 2) return -1; + tkey->htype = sel->extended ? + TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 : + TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK; + if (strcmp(*argv, "src") == 0) { NEXT_ARG(); tkey->off = 12; - res = parse_cmd(&argc, &argv, 4, TIPV4,RU32,sel,tkey); + res = parse_cmd(&argc, &argv, 4, TIPV4, RU32, sel, tkey); goto done; } if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); tkey->off = 16; - res = parse_cmd(&argc, &argv, 4, TIPV4,RU32,sel,tkey); + res = parse_cmd(&argc, &argv, 4, TIPV4, RU32, sel, tkey); goto done; } /* jamal - look at these and make them either old or new @@ -52,108 +57,107 @@ parse_ip(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_ke if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { NEXT_ARG(); tkey->off = 1; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } if (strcmp(*argv, "ihl") == 0) { NEXT_ARG(); tkey->off = 0; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x0f, sel, tkey); + goto done; + } + if (strcmp(*argv, "ttl") == 0) { + NEXT_ARG(); + tkey->off = 8; + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } if (strcmp(*argv, "protocol") == 0) { NEXT_ARG(); tkey->off = 9; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } /* jamal - fix this */ if (matches(*argv, "precedence") == 0) { NEXT_ARG(); tkey->off = 1; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } /* jamal - validate this at some point */ if (strcmp(*argv, "nofrag") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x3F,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x3F, sel, tkey); goto done; } /* jamal - validate this at some point */ if (strcmp(*argv, "firstfrag") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x1F,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x1F, sel, tkey); goto done; } if (strcmp(*argv, "ce") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x80,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x80, sel, tkey); goto done; } if (strcmp(*argv, "df") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x40,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x40, sel, tkey); goto done; } if (strcmp(*argv, "mf") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x20,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x20, sel, tkey); goto done; } + + if (sel->extended) + return -1; /* fields located outside IP header should be + * addressed using the relevant header type in + * extended pedit kABI + */ + if (strcmp(*argv, "dport") == 0) { NEXT_ARG(); tkey->off = 22; - res = parse_cmd(&argc, &argv, 2, TU32,RU16,sel,tkey); + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); goto done; } if (strcmp(*argv, "sport") == 0) { NEXT_ARG(); tkey->off = 20; - res = parse_cmd(&argc, &argv, 2, TU32,RU16,sel,tkey); + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); goto done; } if (strcmp(*argv, "icmp_type") == 0) { NEXT_ARG(); tkey->off = 20; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } if (strcmp(*argv, "icmp_code") == 0) { NEXT_ARG(); tkey->off = 20; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } return -1; - done: +done: *argc_p = argc; *argv_p = argv; return res; } -static int -parse_ip6(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) -{ - int res = -1; - return res; -} - struct m_pedit_util p_pedit_ip = { NULL, "ip", parse_ip, }; - - -struct m_pedit_util p_pedit_ip6 = { - NULL, - "ip6", - parse_ip6, -}; diff --git a/tc/p_ip6.c b/tc/p_ip6.c new file mode 100644 index 00000000..a4824bda --- /dev/null +++ b/tc/p_ip6.c @@ -0,0 +1,91 @@ +/* + * p_ip6.c packet editor: IPV6 header + * + * This program is free software; you can distribute 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: Amir Vadai <amir@vadai.me> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include "utils.h" +#include "tc_util.h" +#include "m_pedit.h" + +static int +parse_ip6(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, struct m_pedit_key *tkey) +{ + int res = -1; + int argc = *argc_p; + char **argv = *argv_p; + + if (argc < 2) + return -1; + + if (!sel->extended) + return -1; + + tkey->htype = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6; + + if (strcmp(*argv, "src") == 0) { + NEXT_ARG(); + tkey->off = 8; + res = parse_cmd(&argc, &argv, 16, TIPV6, RU32, sel, tkey); + goto done; + } + if (strcmp(*argv, "dst") == 0) { + NEXT_ARG(); + tkey->off = 24; + res = parse_cmd(&argc, &argv, 16, TIPV6, RU32, sel, tkey); + goto done; + } + if (strcmp(*argv, "flow_lbl") == 0) { + NEXT_ARG(); + tkey->off = 0; + res = parse_cmd(&argc, &argv, 4, TU32, 0x0007ffff, sel, tkey); + goto done; + } + if (strcmp(*argv, "payload_len") == 0) { + NEXT_ARG(); + tkey->off = 4; + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); + goto done; + } + if (strcmp(*argv, "nexthdr") == 0) { + NEXT_ARG(); + tkey->off = 6; + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); + goto done; + } + if (strcmp(*argv, "hoplimit") == 0) { + NEXT_ARG(); + tkey->off = 7; + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); + goto done; + } + + return -1; + +done: + *argc_p = argc; + *argv_p = argv; + return res; +} + +struct m_pedit_util p_pedit_ip6 = { + NULL, + "ipv6", + parse_ip6, +}; @@ -24,9 +24,47 @@ #include "m_pedit.h" static int -parse_tcp(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_tcp(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, struct m_pedit_key *tkey) { int res = -1; + int argc = *argc_p; + char **argv = *argv_p; + + if (argc < 2) + return -1; + + if (!sel->extended) + return -1; + + tkey->htype = TCA_PEDIT_KEY_EX_HDR_TYPE_TCP; + + if (strcmp(*argv, "sport") == 0) { + NEXT_ARG(); + tkey->off = 0; + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); + goto done; + } + + if (strcmp(*argv, "dport") == 0) { + NEXT_ARG(); + tkey->off = 2; + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); + goto done; + } + + if (strcmp(*argv, "flags") == 0) { + NEXT_ARG(); + tkey->off = 13; + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); + goto done; + } + + return -1; + +done: + *argc_p = argc; + *argv_p = argv; return res; } struct m_pedit_util p_pedit_tcp = { @@ -24,9 +24,40 @@ #include "m_pedit.h" static int -parse_udp(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_udp(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, struct m_pedit_key *tkey) { int res = -1; + int argc = *argc_p; + char **argv = *argv_p; + + if (argc < 2) + return -1; + + if (!sel->extended) + return -1; + + tkey->htype = TCA_PEDIT_KEY_EX_HDR_TYPE_UDP; + + if (strcmp(*argv, "sport") == 0) { + NEXT_ARG(); + tkey->off = 0; + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); + goto done; + } + + if (strcmp(*argv, "dport") == 0) { + NEXT_ARG(); + tkey->off = 2; + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); + goto done; + } + + return -1; + +done: + *argc_p = argc; + *argv_p = argv; return res; } @@ -30,7 +30,7 @@ static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { if (argc) { - fprintf(stderr,"Usage: atm\n"); + fprintf(stderr, "Usage: atm\n"); return -1; } return 0; @@ -39,17 +39,15 @@ static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl static void explain(void) { - fprintf(stderr, "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) " - "[ qos QOS ] [ sndbuf BYTES ]\n"); - fprintf(stderr, " [ hdr HEX... ] [ excess ( CLASSID | clp ) ] " - "[ clip ]\n"); + fprintf(stderr, "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) [ qos QOS ] [ sndbuf BYTES ]\n"); + fprintf(stderr, " [ hdr HEX... ] [ excess ( CLASSID | clp ) ] [ clip ]\n"); } static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct sockaddr_atmsvc addr; + struct sockaddr_atmsvc addr = {}; struct atm_qos qos; struct atm_sap sap; unsigned char hdr[MAX_HDR_LEN]; @@ -60,52 +58,46 @@ static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, int set_clip = 0; int s; - memset(&addr,0,sizeof(addr)); - (void) text2qos("aal5,ubr:sdu=9180,rx:none",&qos,0); - (void) text2sap("blli:l2=iso8802",&sap,0); + (void) text2qos("aal5,ubr:sdu=9180,rx:none", &qos, 0); + (void) text2sap("blli:l2=iso8802", &sap, 0); while (argc > 0) { - if (!strcmp(*argv,"pvc")) { + if (!strcmp(*argv, "pvc")) { NEXT_ARG(); - if (text2atm(*argv,(struct sockaddr *) &addr, - sizeof(addr),T2A_PVC | T2A_NAME) < 0) { + if (text2atm(*argv, (struct sockaddr *) &addr, + sizeof(addr), T2A_PVC | T2A_NAME) < 0) { explain(); return -1; } - } - else if (!strcmp(*argv,"svc")) { + } else if (!strcmp(*argv,"svc")) { NEXT_ARG(); - if (text2atm(*argv,(struct sockaddr *) &addr, - sizeof(addr),T2A_SVC | T2A_NAME) < 0) { + if (text2atm(*argv, (struct sockaddr *) &addr, + sizeof(addr), T2A_SVC | T2A_NAME) < 0) { explain(); return -1; } - } - else if (!strcmp(*argv,"qos")) { + } else if (!strcmp(*argv,"qos")) { NEXT_ARG(); - if (text2qos(*argv,&qos,0) < 0) { + if (text2qos(*argv, &qos, 0) < 0) { explain(); return -1; } - } - else if (!strcmp(*argv,"sndbuf")) { + } else if (!strcmp(*argv,"sndbuf")) { char *end; NEXT_ARG(); - sndbuf = strtol(*argv,&end,0); + sndbuf = strtol(*argv, &end, 0); if (*end) { explain(); return -1; } - } - else if (!strcmp(*argv,"sap")) { + } else if (!strcmp(*argv,"sap")) { NEXT_ARG(); if (addr.sas_family != AF_ATMSVC || - text2sap(*argv,&sap,T2A_NAME) < 0) { + text2sap(*argv, &sap, T2A_NAME) < 0) { explain(); return -1; } - } - else if (!strcmp(*argv,"hdr")) { + } else if (!strcmp(*argv,"hdr")) { unsigned char *ptr; char *walk; @@ -115,7 +107,7 @@ static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, int tmp; if (ptr == hdr+MAX_HDR_LEN) { - fprintf(stderr,"header is too long\n"); + fprintf(stderr, "header is too long\n"); return -1; } if (*walk == '.') continue; @@ -124,64 +116,61 @@ static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, explain(); return -1; } - sscanf(walk,"%2x",&tmp); + sscanf(walk, "%2x", &tmp); *ptr++ = tmp; walk++; } hdr_len = ptr-hdr; - } - else if (!strcmp(*argv,"excess")) { + } else if (!strcmp(*argv,"excess")) { NEXT_ARG(); - if (!strcmp(*argv,"clp")) excess = 0; - else if (get_tc_classid(&excess,*argv)) { + if (!strcmp(*argv, "clp")) excess = 0; + else if (get_tc_classid(&excess, *argv)) { explain(); return -1; } - } - else if (!strcmp(*argv,"clip")) { + } else if (!strcmp(*argv,"clip")) { set_clip = 1; - } - else { + } else { explain(); return 1; } argc--; argv++; } - s = socket(addr.sas_family,SOCK_DGRAM,0); + s = socket(addr.sas_family, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return -1; } - if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { + if (setsockopt(s, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) { perror("SO_ATMQOS"); return -1; } if (sndbuf) - if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) { perror("SO_SNDBUF"); return -1; } - if (addr.sas_family == AF_ATMSVC && setsockopt(s,SOL_ATM,SO_ATMSAP, - &sap,sizeof(sap)) < 0) { + if (addr.sas_family == AF_ATMSVC && setsockopt(s, SOL_ATM, SO_ATMSAP, + &sap, sizeof(sap)) < 0) { perror("SO_ATMSAP"); return -1; } - if (connect(s,(struct sockaddr *) &addr,addr.sas_family == AF_ATMPVC ? + if (connect(s, (struct sockaddr *) &addr, addr.sas_family == AF_ATMPVC ? sizeof(struct sockaddr_atmpvc) : sizeof(addr)) < 0) { perror("connect"); return -1; } if (set_clip) - if (ioctl(s,ATMARP_MKIP,0) < 0) { + if (ioctl(s, ATMARP_MKIP, 0) < 0) { perror("ioctl ATMARP_MKIP"); return -1; } tail = NLMSG_TAIL(n); - addattr_l(n,1024,TCA_OPTIONS,NULL,0); - addattr_l(n,1024,TCA_ATM_FD,&s,sizeof(s)); - if (excess) addattr_l(n,1024,TCA_ATM_EXCESS,&excess,sizeof(excess)); - if (hdr_len != -1) addattr_l(n,1024,TCA_ATM_HDR,hdr,hdr_len); + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); + addattr_l(n, 1024, TCA_ATM_FD, &s, sizeof(s)); + if (excess) addattr_l(n, 1024, TCA_ATM_EXCESS, &excess, sizeof(excess)); + if (hdr_len != -1) addattr_l(n, 1024, TCA_ATM_HDR, hdr, hdr_len); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -200,37 +189,37 @@ static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_ATM_ADDR]) { if (RTA_PAYLOAD(tb[TCA_ATM_ADDR]) < sizeof(struct sockaddr_atmpvc)) - fprintf(stderr,"ATM: address too short\n"); + fprintf(stderr, "ATM: address too short\n"); else { - if (atm2text(buffer,MAX_ATM_ADDR_LEN, - RTA_DATA(tb[TCA_ATM_ADDR]),A2T_PRETTY | A2T_NAME) < - 0) fprintf(stderr,"atm2text error\n"); - fprintf(f,"pvc %s ",buffer); + if (atm2text(buffer, MAX_ATM_ADDR_LEN, + RTA_DATA(tb[TCA_ATM_ADDR]), A2T_PRETTY | A2T_NAME) < + 0) fprintf(stderr, "atm2text error\n"); + fprintf(f, "pvc %s ", buffer); } } if (tb[TCA_ATM_HDR]) { int i; const __u8 *hdr = RTA_DATA(tb[TCA_ATM_HDR]); - fprintf(f,"hdr"); + fprintf(f, "hdr"); for (i = 0; i < RTA_PAYLOAD(tb[TCA_ATM_HDR]); i++) - fprintf(f,"%c%02x", i ? '.' : ' ', hdr[i]); - if (!i) fprintf(f," ."); - fprintf(f," "); + fprintf(f, "%c%02x", i ? '.' : ' ', hdr[i]); + if (!i) fprintf(f, " ."); + fprintf(f, " "); } if (tb[TCA_ATM_EXCESS]) { __u32 excess; if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS]) < sizeof(excess)) - fprintf(stderr,"ATM: excess class ID too short\n"); + fprintf(stderr, "ATM: excess class ID too short\n"); else { excess = rta_getattr_u32(tb[TCA_ATM_EXCESS]); - if (!excess) fprintf(f,"excess clp "); + if (!excess) fprintf(f, "excess clp "); else { char buf[64]; - print_tc_classid(buf,sizeof(buf),excess); - fprintf(f,"excess %s ",buf); + print_tc_classid(buf, sizeof(buf), excess); + fprintf(f, "excess %s ", buf); } } } @@ -239,10 +228,10 @@ static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) int state; if (RTA_PAYLOAD(tb[TCA_ATM_STATE]) < sizeof(state)) - fprintf(stderr,"ATM: state field too short\n"); + fprintf(stderr, "ATM: state field too short\n"); else { - state = *(int *) RTA_DATA(tb[TCA_ATM_STATE]); - fprintf(f,"%s ",map[state]); + state = rta_getattr_u32(tb[TCA_ATM_STATE]); + fprintf(f, "%s ", map[state]); } } return 0; @@ -250,7 +239,7 @@ static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct qdisc_util atm_qdisc_util = { - .id = "atm", + .id = "atm", .parse_qopt = atm_parse_opt, .print_qopt = atm_print_opt, .parse_copt = atm_parse_class_opt, @@ -49,19 +49,16 @@ static void explain1(char *arg) static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_ratespec r; - struct tc_cbq_lssopt lss; + struct tc_ratespec r = {}; + struct tc_cbq_lssopt lss = {}; __u32 rtab[256]; - unsigned mpu=0, avpkt=0, allot=0; - unsigned short overhead=0; + unsigned mpu = 0, avpkt = 0, allot = 0; + unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ - int cell_log=-1; - int ewma_log=-1; + int cell_log = -1; + int ewma_log = -1; struct rtattr *tail; - memset(&lss, 0, sizeof(lss)); - memset(&r, 0, sizeof(r)); - while (argc > 0) { if (matches(*argv, "bandwidth") == 0 || matches(*argv, "rate") == 0) { @@ -81,17 +78,18 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl return -1; } } else if (matches(*argv, "cell") == 0) { - unsigned cell; + unsigned int cell; int i; + NEXT_ARG(); if (get_size(&cell, *argv)) { explain1("cell"); return -1; } - for (i=0; i<32; i++) + for (i = 0; i < 32; i++) if ((1<<i) == cell) break; - if (i>=32) { + if (i >= 32) { fprintf(stderr, "cell must be 2^n\n"); return -1; } @@ -170,7 +168,8 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024); if (show_raw) { int i; - for (i=0; i<256; i++) + + for (i = 0; i < 256; i++) printf("%u ", rtab[i]); printf("\n"); } @@ -180,28 +179,21 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - int wrr_ok=0, fopt_ok=0; - struct tc_ratespec r; - struct tc_cbq_lssopt lss; - struct tc_cbq_wrropt wrr; - struct tc_cbq_fopt fopt; - struct tc_cbq_ovl ovl; + int wrr_ok = 0, fopt_ok = 0; + struct tc_ratespec r = {}; + struct tc_cbq_lssopt lss = {}; + struct tc_cbq_wrropt wrr = {}; + struct tc_cbq_fopt fopt = {}; __u32 rtab[256]; - unsigned mpu=0; - int cell_log=-1; - int ewma_log=-1; - unsigned bndw = 0; - unsigned minburst=0, maxburst=0; - unsigned short overhead=0; + unsigned mpu = 0; + int cell_log = -1; + int ewma_log = -1; + unsigned int bndw = 0; + unsigned minburst = 0, maxburst = 0; + unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ struct rtattr *tail; - memset(&r, 0, sizeof(r)); - memset(&lss, 0, sizeof(lss)); - memset(&wrr, 0, sizeof(wrr)); - memset(&fopt, 0, sizeof(fopt)); - memset(&ovl, 0, sizeof(ovl)); - while (argc > 0) { if (matches(*argv, "rate") == 0) { NEXT_ARG(); @@ -260,23 +252,25 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str } lss.change |= TCF_CBQ_LSS_EWMA; } else if (matches(*argv, "cell") == 0) { - unsigned cell; + unsigned int cell; int i; + NEXT_ARG(); if (get_size(&cell, *argv)) { explain1("cell"); return -1; } - for (i=0; i<32; i++) + for (i = 0; i < 32; i++) if ((1<<i) == cell) break; - if (i>=32) { + if (i >= 32) { fprintf(stderr, "cell must be 2^n\n"); return -1; } cell_log = i; } else if (matches(*argv, "prio") == 0) { - unsigned prio; + unsigned int prio; + NEXT_ARG(); if (get_u32(&prio, *argv, 0)) { explain1("prio"); @@ -323,6 +317,7 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str fopt_ok++; } else if (matches(*argv, "defmap") == 0) { int err; + NEXT_ARG(); err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange); if (err < 1) { @@ -357,7 +352,8 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str /* 1. Prepare link sharing scheduler parameters */ if (r.rate) { - unsigned pktsize = wrr.allot; + unsigned int pktsize = wrr.allot; + if (wrr.allot < (lss.avpkt*3)/2) wrr.allot = (lss.avpkt*3)/2; r.mpu = mpu; @@ -375,7 +371,7 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str fprintf(stderr, "CBQ: avpkt is required for max/minburst.\n"); return -1; } - if (bndw==0 || r.rate == 0) { + if (bndw == 0 || r.rate == 0) { fprintf(stderr, "CBQ: bandwidth&rate are required for max/minburst.\n"); return -1; } @@ -424,7 +420,8 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024); if (show_raw) { int i; - for (i=0; i<256; i++) + + for (i = 0; i < 256; i++) printf("%u ", rtab[i]); printf("\n"); } @@ -443,6 +440,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct tc_cbq_fopt *fopt = NULL; struct tc_cbq_ovl *ovl = NULL; unsigned int linklayer; + SPRINT_BUF(b1); SPRINT_BUF(b2); @@ -478,14 +476,15 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_CBQ_OVL_STRATEGY]) { if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl)) fprintf(stderr, "CBQ: too short overlimit strategy %u/%u\n", - (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]), - (unsigned) sizeof(*ovl)); + (unsigned int) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]), + (unsigned int) sizeof(*ovl)); else ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]); } if (r) { char buf[64]; + print_rate(buf, sizeof(buf), r->rate); fprintf(f, "rate %s ", buf); linklayer = (r->linklayer & TC_LINKLAYER_MASK); @@ -500,11 +499,12 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } } if (lss && lss->flags) { - int comma=0; + int comma = 0; + fprintf(f, "("); if (lss->flags&TCF_CBQ_LSS_BOUNDED) { fprintf(f, "bounded"); - comma=1; + comma = 1; } if (lss->flags&TCF_CBQ_LSS_ISOLATED) { if (comma) @@ -520,6 +520,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) fprintf(f, "prio no-transmit"); if (show_details) { char buf[64]; + fprintf(f, "/%u ", wrr->cpriority); if (wrr->weight != 1) { print_rate(buf, sizeof(buf), wrr->weight); @@ -536,7 +537,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (show_raw) fprintf(f, "[%08x] ", lss->maxidle); } - if (lss->minidle!=0x7fffffff) { + if (lss->minidle != 0x7fffffff) { fprintf(f, "minidle %s ", sprint_ticks(lss->minidle>>lss->ewma_log, b1)); if (show_raw) fprintf(f, "[%08x] ", lss->minidle); @@ -549,6 +550,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } if (fopt && show_details) { char buf[64]; + print_tc_classid(buf, sizeof(buf), fopt->split); fprintf(f, "\nsplit %s ", buf); if (fopt->defmap) { diff --git a/tc/q_choke.c b/tc/q_choke.c index bd9ceb84..a234d2e0 100644 --- a/tc/q_choke.c +++ b/tc/q_choke.c @@ -34,19 +34,17 @@ static void explain(void) static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_red_qopt opt; - unsigned burst = 0; - unsigned avpkt = 1000; + struct tc_red_qopt opt = {}; + unsigned int burst = 0; + unsigned int avpkt = 1000; double probability = 0.02; - unsigned rate = 0; + unsigned int rate = 0; int ecn_ok = 0; int wlog; __u8 sbuf[256]; __u32 max_P; struct rtattr *tail; - memset(&opt, 0, sizeof(opt)); - while (argc > 0) { if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); diff --git a/tc/q_clsact.c b/tc/q_clsact.c index 0c05dbd3..e2a1a710 100644 --- a/tc/q_clsact.c +++ b/tc/q_clsact.c @@ -18,7 +18,6 @@ static int clsact_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } - addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); return 0; } diff --git a/tc/q_codel.c b/tc/q_codel.c index c24246c5..09222a17 100644 --- a/tc/q_codel.c +++ b/tc/q_codel.c @@ -53,7 +53,7 @@ static void explain(void) { - fprintf(stderr, "Usage: ... codel [ limit PACKETS ] [ target TIME]\n"); + fprintf(stderr, "Usage: ... codel [ limit PACKETS ] [ target TIME ]\n"); fprintf(stderr, " [ interval TIME ] [ ecn | noecn ]\n"); fprintf(stderr, " [ ce_threshold TIME ]\n"); } @@ -61,10 +61,10 @@ static void explain(void) static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - unsigned limit = 0; - unsigned target = 0; - unsigned interval = 0; - unsigned ce_threshold = ~0U; + unsigned int limit = 0; + unsigned int target = 0; + unsigned int interval = 0; + unsigned int ce_threshold = ~0U; int ecn = -1; struct rtattr *tail; @@ -129,11 +129,12 @@ static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_CODEL_MAX + 1]; - unsigned limit; - unsigned interval; - unsigned target; - unsigned ecn; - unsigned ce_threshold; + unsigned int limit; + unsigned int interval; + unsigned int target; + unsigned int ecn; + unsigned int ce_threshold; + SPRINT_BUF(b1); if (opt == NULL) @@ -174,7 +175,8 @@ static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) static int codel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { - struct tc_codel_xstats _st, *st; + struct tc_codel_xstats _st = {}, *st; + SPRINT_BUF(b1); if (xstats == NULL) @@ -182,7 +184,6 @@ static int codel_print_xstats(struct qdisc_util *qu, FILE *f, st = RTA_DATA(xstats); if (RTA_PAYLOAD(xstats) < sizeof(*st)) { - memset(&_st, 0, sizeof(_st)); memcpy(&_st, st, RTA_PAYLOAD(xstats)); st = &_st; } @@ -84,6 +84,7 @@ static int drr_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, static int drr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_DRR_MAX + 1]; + SPRINT_BUF(b1); if (opt == NULL) @@ -100,6 +101,7 @@ static int drr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) static int drr_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { struct tc_drr_stats *x; + SPRINT_BUF(b1); if (xstats == NULL) diff --git a/tc/q_dsmark.c b/tc/q_dsmark.c index 05185c00..79dfd9a2 100644 --- a/tc/q_dsmark.c +++ b/tc/q_dsmark.c @@ -21,8 +21,7 @@ static void explain(void) { - fprintf(stderr,"Usage: dsmark indices INDICES [ default_index " - "DEFAULT_INDEX ] [ set_tc_index ]\n"); + fprintf(stderr,"Usage: dsmark indices INDICES [ default_index DEFAULT_INDEX ] [ set_tc_index ]\n"); } @@ -32,32 +31,29 @@ static int dsmark_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct rtattr *tail; __u16 ind; char *end; - int dflt,set_tc_index; + int dflt, set_tc_index; ind = set_tc_index = 0; dflt = -1; while (argc > 0) { - if (!strcmp(*argv,"indices")) { + if (!strcmp(*argv, "indices")) { NEXT_ARG(); - ind = strtoul(*argv,&end,0); + ind = strtoul(*argv, &end, 0); if (*end) { explain(); return -1; } - } - else if (!strcmp(*argv,"default_index") || !strcmp(*argv, + } else if (!strcmp(*argv,"default_index") || !strcmp(*argv, "default")) { NEXT_ARG(); - dflt = strtoul(*argv,&end,0); + dflt = strtoul(*argv, &end, 0); if (*end) { explain(); return -1; } - } - else if (!strcmp(*argv,"set_tc_index")) { + } else if (!strcmp(*argv,"set_tc_index")) { set_tc_index = 1; - } - else { + } else { explain(); return -1; } @@ -69,14 +65,14 @@ static int dsmark_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } tail = NLMSG_TAIL(n); - addattr_l(n,1024,TCA_OPTIONS,NULL,0); - addattr_l(n,1024,TCA_DSMARK_INDICES,&ind,sizeof(ind)); + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); + addattr_l(n, 1024, TCA_DSMARK_INDICES, &ind, sizeof(ind)); if (dflt != -1) { __u16 tmp = dflt; - addattr_l(n,1024,TCA_DSMARK_DEFAULT_INDEX,&tmp,sizeof(tmp)); + addattr_l(n, 1024, TCA_DSMARK_DEFAULT_INDEX, &tmp, sizeof(tmp)); } - if (set_tc_index) addattr_l(n,1024,TCA_DSMARK_SET_TC_INDEX,NULL,0); + if (set_tc_index) addattr_l(n, 1024, TCA_DSMARK_SET_TC_INDEX, NULL, 0); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -96,27 +92,25 @@ static int dsmark_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, char *end; tail = NLMSG_TAIL(n); - addattr_l(n,1024,TCA_OPTIONS,NULL,0); + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); while (argc > 0) { - if (!strcmp(*argv,"mask")) { + if (!strcmp(*argv, "mask")) { NEXT_ARG(); - tmp = strtoul(*argv,&end,0); + tmp = strtoul(*argv, &end, 0); if (*end) { explain_class(); return -1; } - addattr_l(n,1024,TCA_DSMARK_MASK,&tmp,1); - } - else if (!strcmp(*argv,"value")) { + addattr_l(n, 1024, TCA_DSMARK_MASK, &tmp, 1); + } else if (!strcmp(*argv,"value")) { NEXT_ARG(); - tmp = strtoul(*argv,&end,0); + tmp = strtoul(*argv, &end, 0); if (*end) { explain_class(); return -1; } - addattr_l(n,1024,TCA_DSMARK_VALUE,&tmp,1); - } - else { + addattr_l(n, 1024, TCA_DSMARK_VALUE, &tmp, 1); + } else { explain_class(); return -1; } @@ -134,33 +128,32 @@ static int dsmark_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct rtattr *tb[TCA_DSMARK_MAX+1]; if (!opt) return 0; - memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_DSMARK_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)); if (tb[TCA_DSMARK_MASK]) { if (!RTA_PAYLOAD(tb[TCA_DSMARK_MASK])) - fprintf(stderr,"dsmark: empty mask\n"); - else fprintf(f,"mask 0x%02x ", + fprintf(stderr, "dsmark: empty mask\n"); + else fprintf(f, "mask 0x%02x ", rta_getattr_u8(tb[TCA_DSMARK_MASK])); } if (tb[TCA_DSMARK_VALUE]) { if (!RTA_PAYLOAD(tb[TCA_DSMARK_VALUE])) - fprintf(stderr,"dsmark: empty value\n"); - else fprintf(f,"value 0x%02x ", + fprintf(stderr, "dsmark: empty value\n"); + else fprintf(f, "value 0x%02x ", rta_getattr_u8(tb[TCA_DSMARK_VALUE])); } if (tb[TCA_DSMARK_INDICES]) { if (RTA_PAYLOAD(tb[TCA_DSMARK_INDICES]) < sizeof(__u16)) - fprintf(stderr,"dsmark: indices too short\n"); - else fprintf(f,"indices 0x%04x ", + fprintf(stderr, "dsmark: indices too short\n"); + else fprintf(f, "indices 0x%04x ", rta_getattr_u16(tb[TCA_DSMARK_INDICES])); } if (tb[TCA_DSMARK_DEFAULT_INDEX]) { if (RTA_PAYLOAD(tb[TCA_DSMARK_DEFAULT_INDEX]) < sizeof(__u16)) - fprintf(stderr,"dsmark: default_index too short\n"); - else fprintf(f,"default_index 0x%04x ", + fprintf(stderr, "dsmark: default_index too short\n"); + else fprintf(f, "default_index 0x%04x ", rta_getattr_u16(tb[TCA_DSMARK_DEFAULT_INDEX])); } - if (tb[TCA_DSMARK_SET_TC_INDEX]) fprintf(f,"set_tc_index "); + if (tb[TCA_DSMARK_SET_TC_INDEX]) fprintf(f, "set_tc_index "); return 0; } diff --git a/tc/q_fifo.c b/tc/q_fifo.c index c9ab123f..3ee8ce9a 100644 --- a/tc/q_fifo.c +++ b/tc/q_fifo.c @@ -30,9 +30,8 @@ static void explain(void) static int fifo_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - int ok=0; - struct tc_fifo_qopt opt; - memset(&opt, 0, sizeof(opt)); + int ok = 0; + struct tc_fifo_qopt opt = {}; while (argc > 0) { if (strcmp(*argv, "limit") == 0) { @@ -55,6 +55,7 @@ static void explain(void) fprintf(stderr, " [ quantum BYTES ] [ initial_quantum BYTES ]\n"); fprintf(stderr, " [ maxrate RATE ] [ buckets NUMBER ]\n"); fprintf(stderr, " [ [no]pacing ] [ refill_delay TIME ]\n"); + fprintf(stderr, " [ low_rate_threshold RATE ]\n"); fprintf(stderr, " [ orphan_mask MASK]\n"); } @@ -79,6 +80,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv, unsigned int initial_quantum; unsigned int buckets = 0; unsigned int maxrate; + unsigned int low_rate_threshold; unsigned int defrate; unsigned int refill_delay; unsigned int orphan_mask; @@ -90,6 +92,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv, bool set_defrate = false; bool set_refill_delay = false; bool set_orphan_mask = false; + bool set_low_rate_threshold = false; int pacing = -1; struct rtattr *tail; @@ -121,6 +124,13 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } set_maxrate = true; + } else if (strcmp(*argv, "low_rate_threshold") == 0) { + NEXT_ARG(); + if (get_rate(&low_rate_threshold, *argv)) { + fprintf(stderr, "Illegal \"low_rate_threshold\"\n"); + return -1; + } + set_low_rate_threshold = true; } else if (strcmp(*argv, "defrate") == 0) { NEXT_ARG(); if (get_rate(&defrate, *argv)) { @@ -196,6 +206,9 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (set_maxrate) addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE, &maxrate, sizeof(maxrate)); + if (set_low_rate_threshold) + addattr_l(n, 1024, TCA_FQ_LOW_RATE_THRESHOLD, + &low_rate_threshold, sizeof(low_rate_threshold)); if (set_defrate) addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE, &defrate, sizeof(defrate)); @@ -218,6 +231,7 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) unsigned int rate, quantum; unsigned int refill_delay; unsigned int orphan_mask; + SPRINT_BUF(b1); if (opt == NULL) @@ -275,6 +289,13 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (rate != 0) fprintf(f, "defrate %s ", sprint_rate(rate, b1)); } + if (tb[TCA_FQ_LOW_RATE_THRESHOLD] && + RTA_PAYLOAD(tb[TCA_FQ_LOW_RATE_THRESHOLD]) >= sizeof(__u32)) { + rate = rta_getattr_u32(tb[TCA_FQ_LOW_RATE_THRESHOLD]); + + if (rate != 0) + fprintf(f, "low_rate_threshold %s ", sprint_rate(rate, b1)); + } if (tb[TCA_FQ_FLOW_REFILL_DELAY] && RTA_PAYLOAD(tb[TCA_FQ_FLOW_REFILL_DELAY]) >= sizeof(__u32)) { refill_delay = rta_getattr_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]); @@ -311,6 +332,9 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f, fprintf(f, ", %llu throttled", st->throttled); + if (st->unthrottle_latency_ns) + fprintf(f, ", %u ns latency", st->unthrottle_latency_ns); + if (st->flows_plimit) fprintf(f, ", %llu flows_plimit", st->flows_plimit); diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index 4f747ebd..500e6206 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -51,7 +51,7 @@ static void explain(void) { fprintf(stderr, "Usage: ... fq_codel [ limit PACKETS ] [ flows NUMBER ]\n"); - fprintf(stderr, " [ target TIME] [ interval TIME ]\n"); + fprintf(stderr, " [ target TIME ] [ interval TIME ]\n"); fprintf(stderr, " [ quantum BYTES ] [ [no]ecn ]\n"); fprintf(stderr, " [ ce_threshold TIME ]\n"); } @@ -59,12 +59,13 @@ static void explain(void) static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - unsigned limit = 0; - unsigned flows = 0; - unsigned target = 0; - unsigned interval = 0; - unsigned quantum = 0; - unsigned ce_threshold = ~0U; + unsigned int limit = 0; + unsigned int flows = 0; + unsigned int target = 0; + unsigned int interval = 0; + unsigned int quantum = 0; + unsigned int ce_threshold = ~0U; + unsigned int memory = ~0U; int ecn = -1; struct rtattr *tail; @@ -99,6 +100,12 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, fprintf(stderr, "Illegal \"ce_threshold\"\n"); return -1; } + } else if (strcmp(*argv, "memory_limit") == 0) { + NEXT_ARG(); + if (get_size(&memory, *argv)) { + fprintf(stderr, "Illegal \"memory_limit\"\n"); + return -1; + } } else if (strcmp(*argv, "interval") == 0) { NEXT_ARG(); if (get_time(&interval, *argv)) { @@ -137,6 +144,10 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (ce_threshold != ~0U) addattr_l(n, 1024, TCA_FQ_CODEL_CE_THRESHOLD, &ce_threshold, sizeof(ce_threshold)); + if (memory != ~0U) + addattr_l(n, 1024, TCA_FQ_CODEL_MEMORY_LIMIT, + &memory, sizeof(memory)); + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -144,13 +155,15 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_FQ_CODEL_MAX + 1]; - unsigned limit; - unsigned flows; - unsigned interval; - unsigned target; - unsigned ecn; - unsigned quantum; - unsigned ce_threshold; + unsigned int limit; + unsigned int flows; + unsigned int interval; + unsigned int target; + unsigned int ecn; + unsigned int quantum; + unsigned int ce_threshold; + unsigned int memory_limit; + SPRINT_BUF(b1); if (opt == NULL) @@ -188,6 +201,12 @@ static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt interval = rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); fprintf(f, "interval %s ", sprint_time(interval, b1)); } + if (tb[TCA_FQ_CODEL_MEMORY_LIMIT] && + RTA_PAYLOAD(tb[TCA_FQ_CODEL_MEMORY_LIMIT]) >= sizeof(__u32)) { + memory_limit = rta_getattr_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]); + + fprintf(f, "memory_limit %s ", sprint_size(memory_limit, b1)); + } if (tb[TCA_FQ_CODEL_ECN] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >= sizeof(__u32)) { ecn = rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); @@ -201,7 +220,8 @@ static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { - struct tc_fq_codel_xstats _st, *st; + struct tc_fq_codel_xstats _st = {}, *st; + SPRINT_BUF(b1); if (xstats == NULL) @@ -209,7 +229,6 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, st = RTA_DATA(xstats); if (RTA_PAYLOAD(xstats) < sizeof(*st)) { - memset(&_st, 0, sizeof(_st)); memcpy(&_st, st, RTA_PAYLOAD(xstats)); st = &_st; } @@ -221,6 +240,10 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, st->qdisc_stats.ecn_mark); if (st->qdisc_stats.ce_mark) fprintf(f, " ce_mark %u", st->qdisc_stats.ce_mark); + if (st->qdisc_stats.memory_usage) + fprintf(f, " memory_used %u", st->qdisc_stats.memory_usage); + if (st->qdisc_stats.drop_overmemory) + fprintf(f, " drop_overmemory %u", st->qdisc_stats.drop_overmemory); fprintf(f, "\n new_flows_len %u old_flows_len %u", st->qdisc_stats.new_flows_len, st->qdisc_stats.old_flows_len); diff --git a/tc/q_gred.c b/tc/q_gred.c index f31daa37..0a989496 100644 --- a/tc/q_gred.c +++ b/tc/q_gred.c @@ -30,9 +30,9 @@ #if 0 -#define DPRINTF(format,args...) fprintf(stderr,format,##args) +#define DPRINTF(format, args...) fprintf(stderr, format, ##args) #else -#define DPRINTF(format,args...) +#define DPRINTF(format, args...) #endif static void explain(void) @@ -55,7 +55,7 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, opt.def_DP = MAX_DPs; while (argc > 0) { - DPRINTF(stderr,"init_gred: invoked with %s\n",*argv); + DPRINTF(stderr, "init_gred: invoked with %s\n", *argv); if (strcmp(*argv, "vqs") == 0 || strcmp(*argv, "DPs") == 0) { NEXT_ARG(); @@ -63,14 +63,13 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, fprintf(stderr, "Illegal \"vqs\"\n"); return -1; } else if (opt.DPs > MAX_DPs) { - fprintf(stderr, "GRED: only %u VQs are " - "currently supported\n", MAX_DPs); + fprintf(stderr, "GRED: only %u VQs are currently supported\n", + MAX_DPs); return -1; } } else if (strcmp(*argv, "default") == 0) { if (opt.DPs == 0) { - fprintf(stderr, "\"default\" must be defined " - "after \"vqs\"\n"); + fprintf(stderr, "\"default\" must be defined after \"vqs\"\n"); return -1; } NEXT_ARG(); @@ -78,8 +77,7 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, fprintf(stderr, "Illegal \"default\"\n"); return -1; } else if (opt.def_DP >= opt.DPs) { - fprintf(stderr, "\"default\" must be less than " - "\"vqs\"\n"); + fprintf(stderr, "\"default\" must be less than \"vqs\"\n"); return -1; } } else if (strcmp(*argv, "grio") == 0) { @@ -102,12 +100,12 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, } if (!opt.DPs || opt.def_DP == MAX_DPs) { - fprintf(stderr, "Illegal gred setup parameters \n"); + fprintf(stderr, "Illegal gred setup parameters\n"); return -1; } - DPRINTF("TC_GRED: sending DPs=%u def_DP=%u\n",opt.DPs,opt.def_DP); - n->nlmsg_flags|=NLM_F_CREATE; + DPRINTF("TC_GRED: sending DPs=%u def_DP=%u\n", opt.DPs, opt.def_DP); + n->nlmsg_flags |= NLM_F_CREATE; tail = NLMSG_TAIL(n); addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); addattr_l(n, 1024, TCA_GRED_DPS, &opt, sizeof(struct tc_gred_sopt)); @@ -121,12 +119,12 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, */ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - int ok=0; + int ok = 0; struct tc_gred_qopt opt = { 0 }; - unsigned burst = 0; - unsigned avpkt = 0; + unsigned int burst = 0; + unsigned int avpkt = 0; double probability = 0.02; - unsigned rate = 0; + unsigned int rate = 0; int parm; __u8 sbuf[256]; struct rtattr *tail; @@ -169,8 +167,8 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n fprintf(stderr, "Illegal \"vq\"\n"); return -1; } else if (opt.DP >= MAX_DPs) { - fprintf(stderr, "GRED: only %u VQs are " - "currently supported\n", MAX_DPs); + fprintf(stderr, "GRED: only %u VQs are currently supported\n", + MAX_DPs); return -1; } /* need a better error check */ ok++; @@ -197,7 +195,7 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n ok++; } else if (strcmp(*argv, "prio") == 0) { NEXT_ARG(); - opt.prio=strtol(*argv, (char **)NULL, 10); + opt.prio = strtol(*argv, (char **)NULL, 10); /* some error check here */ ok++; } else if (strcmp(*argv, "bandwidth") == 0) { @@ -224,8 +222,7 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n } if (opt.DP == MAX_DPs || !opt.limit || !opt.qth_min || !opt.qth_max || !avpkt) { - fprintf(stderr, "Required parameter (vq, limit, min, max, " - "avpkt) is missing\n"); + fprintf(stderr, "Required parameter (vq, limit, min, max, avpkt) is missing\n"); return -1; } if (!burst) { @@ -241,8 +238,8 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n return -1; } if (parm >= 10) - fprintf(stderr, "GRED: WARNING. Burst %u seems to be too " - "large.\n", burst); + fprintf(stderr, "GRED: WARNING. Burst %u seems to be too large.\n", + burst); opt.Wlog = parm; if ((parm = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) { fprintf(stderr, "GRED: failed to calculate probability.\n"); @@ -251,8 +248,7 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n opt.Plog = parm; if ((parm = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) { - fprintf(stderr, "GRED: failed to calculate idle damping " - "table.\n"); + fprintf(stderr, "GRED: failed to calculate idle damping table.\n"); return -1; } opt.Scell_log = parm; @@ -274,7 +270,8 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct tc_gred_qopt *qopt; __u32 *max_p = NULL; __u32 *limit = NULL; - unsigned i; + unsigned int i; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); @@ -299,7 +296,7 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) qopt = RTA_DATA(tb[TCA_GRED_PARMS]); if (RTA_PAYLOAD(tb[TCA_GRED_DPS]) < sizeof(*sopt) || RTA_PAYLOAD(tb[TCA_GRED_PARMS]) < sizeof(*qopt)*MAX_DPs) { - fprintf(f,"\n GRED received message smaller than expected\n"); + fprintf(f, "\n GRED received message smaller than expected\n"); return -1; } @@ -314,7 +311,7 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) fprintf(f, "limit %s ", sprint_size(*limit, b1)); - for (i=0;i<MAX_DPs;i++, qopt++) { + for (i = 0; i < MAX_DPs; i++, qopt++) { if (qopt->DP >= MAX_DPs) continue; fprintf(f, "\n vq %u prio %hhu limit %s min %s max %s ", qopt->DP, diff --git a/tc/q_hfsc.c b/tc/q_hfsc.c index 03539ec1..cf784f15 100644 --- a/tc/q_hfsc.c +++ b/tc/q_hfsc.c @@ -73,9 +73,7 @@ explain1(char *arg) static int hfsc_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_hfsc_qopt qopt; - - memset(&qopt, 0, sizeof(qopt)); + struct tc_hfsc_qopt qopt = {}; while (argc > 0) { if (matches(*argv, "default") == 0) { @@ -144,17 +142,12 @@ hfsc_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) static int hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, - struct nlmsghdr *n) + struct nlmsghdr *n) { - struct tc_service_curve rsc, fsc, usc; - int rsc_ok, fsc_ok, usc_ok; + struct tc_service_curve rsc = {}, fsc = {}, usc = {}; + int rsc_ok = 0, fsc_ok = 0, usc_ok = 0; struct rtattr *tail; - memset(&rsc, 0, sizeof(rsc)); - memset(&fsc, 0, sizeof(fsc)); - memset(&usc, 0, sizeof(usc)); - rsc_ok = fsc_ok = usc_ok = 0; - while (argc > 0) { if (matches(*argv, "rt") == 0) { NEXT_ARG(); @@ -203,8 +196,7 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } if (usc_ok && !fsc_ok) { - fprintf(stderr, "HFSC: Upper-limit Service Curve without " - "Link-Share Service Curve\n"); + fprintf(stderr, "HFSC: Upper-limit Service Curve without Link-Share Service Curve\n"); explain_class(); return -1; } @@ -28,13 +28,13 @@ static void explain(void) static int hhf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - unsigned limit = 0; - unsigned quantum = 0; - unsigned hh_limit = 0; - unsigned reset_timeout = 0; - unsigned admit_bytes = 0; - unsigned evict_timeout = 0; - unsigned non_hh_weight = 0; + unsigned int limit = 0; + unsigned int quantum = 0; + unsigned int hh_limit = 0; + unsigned int reset_timeout = 0; + unsigned int admit_bytes = 0; + unsigned int evict_timeout = 0; + unsigned int non_hh_weight = 0; struct rtattr *tail; while (argc > 0) { @@ -120,13 +120,14 @@ static int hhf_parse_opt(struct qdisc_util *qu, int argc, char **argv, static int hhf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_HHF_MAX + 1]; - unsigned limit; - unsigned quantum; - unsigned hh_limit; - unsigned reset_timeout; - unsigned admit_bytes; - unsigned evict_timeout; - unsigned non_hh_weight; + unsigned int limit; + unsigned int quantum; + unsigned int hh_limit; + unsigned int reset_timeout; + unsigned int admit_bytes; + unsigned int evict_timeout; + unsigned int non_hh_weight; + SPRINT_BUF(b1); if (opt == NULL) @@ -49,7 +49,7 @@ static void explain(void) " mtu max packet size we create rate map for {1600}\n" " prio priority of leaf; lower are served first {0}\n" " quantum how much bytes to serve from leaf at once {use r2q}\n" - "\nTC HTB version %d.%d\n",HTB_TC_VER>>16,HTB_TC_VER&0xffff + "\nTC HTB version %d.%d\n", HTB_TC_VER>>16, HTB_TC_VER&0xffff ); } @@ -63,12 +63,12 @@ static void explain1(char *arg) static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { unsigned int direct_qlen = ~0U; - struct tc_htb_glob opt; + struct tc_htb_glob opt = { + .rate2quantum = 10, + .version = 3, + }; struct rtattr *tail; - unsigned i; char *p; - memset(&opt,0,sizeof(opt)); - opt.rate2quantum = 10; - opt.version = 3; + unsigned int i; char *p; while (argc > 0) { if (matches(*argv, "r2q") == 0) { @@ -83,8 +83,8 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl } } else if (matches(*argv, "debug") == 0) { NEXT_ARG(); p = *argv; - for (i=0; i<16; i++,p++) { - if (*p<'0' || *p>'3') break; + for (i = 0; i < 16; i++, p++) { + if (*p < '0' || *p > '3') break; opt.debug |= (*p-'0')<<(2*i); } } else if (matches(*argv, "direct_qlen") == 0) { @@ -111,20 +111,18 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - int ok=0; - struct tc_htb_opt opt; - __u32 rtab[256],ctab[256]; - unsigned buffer=0,cbuffer=0; - int cell_log=-1,ccell_log = -1; - unsigned mtu; + int ok = 0; + struct tc_htb_opt opt = {}; + __u32 rtab[256], ctab[256]; + unsigned buffer = 0, cbuffer = 0; + int cell_log = -1, ccell_log = -1; + unsigned int mtu = 1600; /* eth packet len */ unsigned short mpu = 0; unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ struct rtattr *tail; __u64 ceil64 = 0, rate64 = 0; - memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */ - while (argc > 0) { if (matches(*argv, "prio") == 0) { NEXT_ARG(); @@ -268,13 +266,13 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct rtattr *tb[TCA_HTB_MAX + 1]; struct tc_htb_opt *hopt; struct tc_htb_glob *gopt; - double buffer,cbuffer; + double buffer, cbuffer; unsigned int linklayer; __u64 rate64, ceil64; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); - SPRINT_BUF(b4); if (opt == NULL) return 0; @@ -311,18 +309,16 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) cbuffer = tc_calc_xmitsize(ceil64, hopt->cbuffer); linklayer = (hopt->rate.linklayer & TC_LINKLAYER_MASK); if (linklayer > TC_LINKLAYER_ETHERNET || show_details) - fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b4)); + fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b3)); if (show_details) { - fprintf(f, "burst %s/%u mpu %s overhead %s ", + fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1), 1<<hopt->rate.cell_log, - sprint_size(hopt->rate.mpu&0xFF, b2), - sprint_size((hopt->rate.mpu>>8)&0xFF, b3)); - fprintf(f, "cburst %s/%u mpu %s overhead %s ", + sprint_size(hopt->rate.mpu, b2)); + fprintf(f, "cburst %s/%u mpu %s ", sprint_size(cbuffer, b1), 1<<hopt->ceil.cell_log, - sprint_size(hopt->ceil.mpu&0xFF, b2), - sprint_size((hopt->ceil.mpu>>8)&0xFF, b3)); + sprint_size(hopt->ceil.mpu, b2)); fprintf(f, "level %d ", (int)hopt->level); } else { fprintf(f, "burst %s ", sprint_size(buffer, b1)); @@ -330,16 +326,16 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } if (show_raw) fprintf(f, "buffer [%08x] cbuffer [%08x] ", - hopt->buffer,hopt->cbuffer); + hopt->buffer, hopt->cbuffer); } if (tb[TCA_HTB_INIT]) { gopt = RTA_DATA(tb[TCA_HTB_INIT]); if (RTA_PAYLOAD(tb[TCA_HTB_INIT]) < sizeof(*gopt)) return -1; fprintf(f, "r2q %d default %x direct_packets_stat %u", - gopt->rate2quantum,gopt->defcls,gopt->direct_pkts); + gopt->rate2quantum, gopt->defcls, gopt->direct_pkts); if (show_details) - fprintf(f," ver %d.%d",gopt->version >> 16,gopt->version & 0xffff); + fprintf(f, " ver %d.%d", gopt->version >> 16, gopt->version & 0xffff); } if (tb[TCA_HTB_DIRECT_QLEN] && RTA_PAYLOAD(tb[TCA_HTB_DIRECT_QLEN]) >= sizeof(__u32)) { @@ -353,6 +349,7 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) static int htb_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { struct tc_htb_xstats *st; + if (xstats == NULL) return 0; @@ -361,16 +358,16 @@ static int htb_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstat st = RTA_DATA(xstats); fprintf(f, " lended: %u borrowed: %u giants: %u\n", - st->lends,st->borrows,st->giants); - fprintf(f, " tokens: %d ctokens: %d\n", st->tokens,st->ctokens); + st->lends, st->borrows, st->giants); + fprintf(f, " tokens: %d ctokens: %d\n", st->tokens, st->ctokens); return 0; } struct qdisc_util htb_qdisc_util = { - .id = "htb", + .id = "htb", .parse_qopt = htb_parse_opt, .print_qopt = htb_print_opt, - .print_xstats = htb_print_xstats, + .print_xstats = htb_print_xstats, .parse_copt = htb_parse_class_opt, .print_copt = htb_print_opt, }; diff --git a/tc/q_ingress.c b/tc/q_ingress.c index c3c9b403..31699a81 100644 --- a/tc/q_ingress.c +++ b/tc/q_ingress.c @@ -34,7 +34,6 @@ static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv, } } - addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); return 0; } diff --git a/tc/q_mqprio.c b/tc/q_mqprio.c index fa1022be..d6718fb1 100644 --- a/tc/q_mqprio.c +++ b/tc/q_mqprio.c @@ -34,10 +34,12 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc, { int idx; struct tc_mqprio_qopt opt = { - 8, - {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 1, 3, 3, 3, 3}, - 1, - }; + .num_tc = 8, + .prio_tc_map = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 1, 3, 3, 3, 3 }, + .hw = 1, + .count = { }, + .offset = { }, + }; while (argc > 0) { idx = 0; diff --git a/tc/q_multiq.c b/tc/q_multiq.c index f4f41f78..9c09c9a7 100644 --- a/tc/q_multiq.c +++ b/tc/q_multiq.c @@ -43,7 +43,7 @@ static void explain(void) static int multiq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_multiq_qopt opt; + struct tc_multiq_qopt opt = {}; if (argc) { if (strcmp(*argv, "help") == 0) { @@ -77,7 +77,7 @@ static int multiq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } struct qdisc_util multiq_qdisc_util = { - .id = "multiq", + .id = "multiq", .parse_qopt = multiq_parse_opt, .print_qopt = multiq_print_opt, }; diff --git a/tc/q_netem.c b/tc/q_netem.c index 7bc8c6a5..cdaddce9 100644 --- a/tc/q_netem.c +++ b/tc/q_netem.c @@ -30,10 +30,10 @@ static void explain(void) { fprintf(stderr, -"Usage: ... netem [ limit PACKETS ] \n" \ +"Usage: ... netem [ limit PACKETS ]\n" \ " [ delay TIME [ JITTER [CORRELATION]]]\n" \ " [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ -" [ corrupt PERCENT [CORRELATION]] \n" \ +" [ corrupt PERCENT [CORRELATION]]\n" \ " [ duplicate PERCENT [CORRELATION]]\n" \ " [ loss random PERCENT [CORRELATION]]\n" \ " [ loss state P13 [P31 [P32 [P23 P14]]]\n" \ @@ -58,7 +58,7 @@ static const double max_percent_value = 0xffffffff; /* scaled value used to percent of maximum. */ static void set_percent(__u32 *percent, double per) { - *percent = (unsigned) rint(per * max_percent_value); + *percent = (unsigned int) rint(per * max_percent_value); } @@ -70,7 +70,7 @@ static int parse_percent(double *val, const char *str) char *p; *val = strtod(str, &p) / 100.; - if (*p && strcmp(p, "%") ) + if (*p && strcmp(p, "%")) return -1; return 0; @@ -92,7 +92,7 @@ static void print_percent(char *buf, int len, __u32 per) snprintf(buf, len, "%g%%", 100. * (double) per / max_percent_value); } -static char * sprint_percent(__u32 per, char *buf) +static char *sprint_percent(__u32 per, char *buf) { print_percent(buf, SPRINT_BSIZE-1, per); return buf; @@ -123,6 +123,7 @@ static int get_distribution(const char *type, __s16 *data, int maxdata) n = 0; while (getline(&line, &len, f) != -1) { char *p, *endp; + if (*line == '\n' || *line == '#') continue; @@ -154,9 +155,9 @@ static int get_distribution(const char *type, __s16 *data, int maxdata) (based on kernel PSCHED_CLOCK configuration */ static int get_ticks(__u32 *ticks, const char *str) { - unsigned t; + unsigned int t; - if(get_time(&t, str)) + if (get_time(&t, str)) return -1; if (tc_core_time2big(t)) { @@ -174,24 +175,18 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, int dist_size = 0; struct rtattr *tail; struct tc_netem_qopt opt = { .limit = 1000 }; - struct tc_netem_corr cor; - struct tc_netem_reorder reorder; - struct tc_netem_corrupt corrupt; + struct tc_netem_corr cor = {}; + struct tc_netem_reorder reorder = {}; + struct tc_netem_corrupt corrupt = {}; struct tc_netem_gimodel gimodel; struct tc_netem_gemodel gemodel; - struct tc_netem_rate rate; + struct tc_netem_rate rate = {}; __s16 *dist_data = NULL; __u16 loss_type = NETEM_LOSS_UNSPEC; - int present[__TCA_NETEM_MAX]; + int present[__TCA_NETEM_MAX] = {}; __u64 rate64 = 0; - memset(&cor, 0, sizeof(cor)); - memset(&reorder, 0, sizeof(reorder)); - memset(&corrupt, 0, sizeof(corrupt)); - memset(&rate, 0, sizeof(rate)); - memset(present, 0, sizeof(present)); - - for( ; argc > 0; --argc, ++argv) { + for ( ; argc > 0; --argc, ++argv) { if (matches(*argv, "limit") == 0) { NEXT_ARG(); if (get_size(&opt.limit, *argv)) { @@ -236,7 +231,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (!strcmp(*argv, "random")) { NEXT_ARG(); - random_loss_model: + random_loss_model: if (get_percent(&opt.loss, *argv)) { explain1("loss percent"); return -1; @@ -343,7 +338,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } } else if (matches(*argv, "ecn") == 0) { - present[TCA_NETEM_ECN] = 1; + present[TCA_NETEM_ECN] = 1; } else if (matches(*argv, "reorder") == 0) { NEXT_ARG(); present[TCA_NETEM_REORDER] = 1; @@ -474,7 +469,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (present[TCA_NETEM_CORR] && addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0) - return -1; + return -1; if (present[TCA_NETEM_REORDER] && addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0) @@ -483,7 +478,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (present[TCA_NETEM_ECN] && addattr_l(n, 1024, TCA_NETEM_ECN, &present[TCA_NETEM_ECN], sizeof(present[TCA_NETEM_ECN])) < 0) - return -1; + return -1; if (present[TCA_NETEM_CORRUPT] && addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0) @@ -496,11 +491,11 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (loss_type == NETEM_LOSS_GI) { if (addattr_l(n, 1024, NETEM_LOSS_GI, &gimodel, sizeof(gimodel)) < 0) - return -1; + return -1; } else if (loss_type == NETEM_LOSS_GE) { if (addattr_l(n, 1024, NETEM_LOSS_GE, &gemodel, sizeof(gemodel)) < 0) - return -1; + return -1; } else { fprintf(stderr, "loss in the weeds!\n"); return -1; @@ -543,13 +538,15 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) int *ecn = NULL; struct tc_netem_qopt qopt; const struct tc_netem_rate *rate = NULL; - int len = RTA_PAYLOAD(opt) - sizeof(qopt); + int len; __u64 rate64 = 0; + SPRINT_BUF(b1); if (opt == NULL) return 0; + len = RTA_PAYLOAD(opt) - sizeof(qopt); if (len < 0) { fprintf(stderr, "options size error\n"); return -1; @@ -558,6 +555,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (len > 0) { struct rtattr *tb[TCA_NETEM_MAX+1]; + parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt), len); @@ -684,7 +682,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } struct qdisc_util netem_qdisc_util = { - .id = "netem", + .id = "netem", .parse_qopt = netem_parse_opt, .print_qopt = netem_print_opt, }; @@ -37,9 +37,7 @@ static void explain(void) } #define ALPHA_MAX 32 -#define ALPHA_MIN 0 #define BETA_MAX 32 -#define BETA_MIN 0 static int pie_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) @@ -75,14 +73,14 @@ static int pie_parse_opt(struct qdisc_util *qu, int argc, char **argv, } else if (strcmp(*argv, "alpha") == 0) { NEXT_ARG(); if (get_unsigned(&alpha, *argv, 0) || - (alpha > ALPHA_MAX) || (alpha < ALPHA_MIN)) { + (alpha > ALPHA_MAX)) { fprintf(stderr, "Illegal \"alpha\"\n"); return -1; } } else if (strcmp(*argv, "beta") == 0) { NEXT_ARG(); if (get_unsigned(&beta, *argv, 0) || - (beta > BETA_MAX) || (beta < BETA_MIN)) { + (beta > BETA_MAX)) { fprintf(stderr, "Illegal \"beta\"\n"); return -1; } @@ -136,8 +134,9 @@ static int pie_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) unsigned int target; unsigned int alpha; unsigned int beta; - unsigned ecn; - unsigned bytemode; + unsigned int ecn; + unsigned int bytemode; + SPRINT_BUF(b1); if (opt == NULL) diff --git a/tc/q_prio.c b/tc/q_prio.c index 3236bec1..a28928a8 100644 --- a/tc/q_prio.c +++ b/tc/q_prio.c @@ -32,7 +32,7 @@ static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n { int pmap_mode = 0; int idx = 0; - struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }}; + struct tc_prio_qopt opt = {3, { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 } }; struct rtattr *nest; unsigned char mq = 0; @@ -57,7 +57,8 @@ static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n explain(); return -1; } else { - unsigned band; + unsigned int band; + if (!pmap_mode) { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); @@ -104,10 +105,10 @@ int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt))) - return -1; + return -1; fprintf(f, "bands %u priomap ", qopt->bands); - for (i=0; i<=TC_PRIO_MAX; i++) + for (i = 0; i <= TC_PRIO_MAX; i++) fprintf(f, " %d", qopt->priomap[i]); if (tb[TCA_PRIO_MQ]) @@ -118,7 +119,7 @@ int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } struct qdisc_util prio_qdisc_util = { - .id = "prio", + .id = "prio", .parse_qopt = prio_parse_opt, .print_qopt = prio_print_opt, }; @@ -38,16 +38,11 @@ static void explain_class(void) static int qfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - while (argc > 0) { - if (matches(*argv, "help") == 0) { - explain(); - return -1; - } else { + if (argc > 0) { + if (matches(*argv, "help") != 0) fprintf(stderr, "What is \"%s\"?\n", *argv); - explain(); - return -1; - } - argc--; argv++; + explain(); + return -1; } return 0; @@ -35,18 +35,16 @@ static void explain(void) static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_red_qopt opt; - unsigned burst = 0; - unsigned avpkt = 0; + struct tc_red_qopt opt = {}; + unsigned int burst = 0; + unsigned int avpkt = 0; double probability = 0.02; - unsigned rate = 0; + unsigned int rate = 0; int parm; __u8 sbuf[256]; __u32 max_P; struct rtattr *tail; - memset(&opt, 0, sizeof(opt)); - while (argc > 0) { if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); @@ -160,6 +158,7 @@ static int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct rtattr *tb[TCA_RED_MAX + 1]; struct tc_red_qopt *qopt; __u32 max_P = 0; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); @@ -33,7 +33,7 @@ static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlm { int pmap_mode = 0; int idx = 0; - struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }}; + struct tc_prio_qopt opt = {3, { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 } }; struct rtattr *nest; unsigned char mq = 0; @@ -58,7 +58,8 @@ static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlm } else if (strcmp(*argv, "multiqueue") == 0) { mq = 1; } else { - unsigned band; + unsigned int band; + if (!pmap_mode) { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); @@ -102,7 +103,7 @@ static int rr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) return -1; fprintf(f, "bands %u priomap ", qopt->bands); - for (i=0; i <= TC_PRIO_MAX; i++) + for (i = 0; i <= TC_PRIO_MAX; i++) fprintf(f, " %d", qopt->priomap[i]); if (tb[TCA_PRIO_MQ]) @@ -113,7 +114,7 @@ static int rr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } struct qdisc_util rr_qdisc_util = { - .id = "rr", + .id = "rr", .parse_qopt = rr_parse_opt, .print_qopt = rr_print_opt, }; @@ -51,17 +51,16 @@ static int get_prob(__u32 *val, const char *arg) static int sfb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_sfb_qopt opt; + struct tc_sfb_qopt opt = { + .rehash_interval = 600*1000, + .warmup_time = 60*1000, + .penalty_rate = 10, + .penalty_burst = 20, + .increment = (SFB_MAX_PROB + 1000) / 2000, + .decrement = (SFB_MAX_PROB + 10000) / 20000, + }; struct rtattr *tail; - memset(&opt, 0, sizeof(opt)); - opt.rehash_interval = 600*1000; - opt.warmup_time = 60*1000; - opt.penalty_rate = 10; - opt.penalty_burst = 20; - opt.increment = (SFB_MAX_PROB + 1000) / 2000; - opt.decrement = (SFB_MAX_PROB + 10000) / 20000; - while (argc > 0) { if (strcmp(*argv, "rehash") == 0) { NEXT_ARG(); @@ -158,8 +157,7 @@ static int sfb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) fprintf(f, "limit %d max %d target %d\n" - " increment %.5f decrement %.5f penalty rate %d burst %d " - "(%ums %ums)", + " increment %.5f decrement %.5f penalty rate %d burst %d (%ums %ums)", qopt->limit, qopt->max, qopt->bin_size, (double)qopt->increment / SFB_MAX_PROB, (double)qopt->decrement / SFB_MAX_PROB, @@ -38,14 +38,12 @@ static void explain(void) static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { int ok = 0, red = 0; - struct tc_sfq_qopt_v1 opt; + struct tc_sfq_qopt_v1 opt = {}; unsigned int burst = 0; int wlog; unsigned int avpkt = 1000; double probability = 0.02; - memset(&opt, 0, sizeof(opt)); - while (argc > 0) { if (strcmp(*argv, "quantum") == 0) { NEXT_ARG(); @@ -207,6 +205,7 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct tc_sfq_qopt *qopt; struct tc_sfq_qopt_v1 *qopt_ext = NULL; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); @@ -38,19 +38,17 @@ static void explain1(const char *arg, const char *val) static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - int ok=0; - struct tc_tbf_qopt opt; + int ok = 0; + struct tc_tbf_qopt opt = {}; __u32 rtab[256]; __u32 ptab[256]; - unsigned buffer=0, mtu=0, mpu=0, latency=0; - int Rcell_log=-1, Pcell_log = -1; - unsigned short overhead=0; + unsigned buffer = 0, mtu = 0, mpu = 0, latency = 0; + int Rcell_log = -1, Pcell_log = -1; + unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ struct rtattr *tail; __u64 rate64 = 0, prate64 = 0; - memset(&opt, 0, sizeof(opt)); - while (argc > 0) { if (matches(*argv, "limit") == 0) { NEXT_ARG(); @@ -86,6 +84,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl strcmp(*argv, "buffer") == 0 || strcmp(*argv, "maxburst") == 0) { const char *parm_name = *argv; + NEXT_ARG(); if (buffer) { fprintf(stderr, "tbf: duplicate \"buffer/burst/maxburst\" specification\n"); @@ -99,6 +98,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl } else if (strcmp(*argv, "mtu") == 0 || strcmp(*argv, "minburst") == 0) { const char *parm_name = *argv; + NEXT_ARG(); if (mtu) { fprintf(stderr, "tbf: duplicate \"mtu/minburst\" specification\n"); @@ -167,12 +167,12 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl argc--; argv++; } - int verdict = 0; + int verdict = 0; - /* Be nice to the user: try to emit all error messages in - * one go rather than reveal one more problem when a - * previous one has been fixed. - */ + /* Be nice to the user: try to emit all error messages in + * one go rather than reveal one more problem when a + * previous one has been fixed. + */ if (rate64 == 0) { fprintf(stderr, "tbf: the \"rate\" parameter is mandatory.\n"); verdict = -1; @@ -193,18 +193,20 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl verdict = -1; } - if (verdict != 0) { - explain(); - return verdict; - } + if (verdict != 0) { + explain(); + return verdict; + } opt.rate.rate = (rate64 >= (1ULL << 32)) ? ~0U : rate64; opt.peakrate.rate = (prate64 >= (1ULL << 32)) ? ~0U : prate64; if (opt.limit == 0) { double lim = rate64*(double)latency/TIME_UNITS_PER_SEC + buffer; + if (prate64) { double lim2 = prate64*(double)latency/TIME_UNITS_PER_SEC + mtu; + if (lim2 < lim) lim = lim2; } @@ -254,6 +256,7 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) double buffer, mtu; double latency; __u64 rate64 = 0, prate64 = 0; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); @@ -305,6 +308,7 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)rate64) - tc_core_tick2time(qopt->buffer); if (prate64) { double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)prate64) - tc_core_tick2time(qopt->mtu); + if (lat2 > latency) latency = lat2; } @@ -31,26 +31,25 @@ #include "tc_common.h" #include "namespace.h" -int show_stats = 0; -int show_details = 0; -int show_raw = 0; -int show_pretty = 0; -int show_graph = 0; +int show_stats; +int show_details; +int show_raw; +int show_pretty; +int show_graph; int timestamp; -int batch_mode = 0; -int resolve_hosts = 0; -int use_iec = 0; -int force = 0; -bool use_names = false; +int batch_mode; +int use_iec; +int force; +bool use_names; static char *conf_file; struct rtnl_handle rth; -static void *BODY = NULL; /* cached handle dlopen(NULL) */ -static struct qdisc_util * qdisc_list; -static struct filter_util * filter_list; +static void *BODY; /* cached handle dlopen(NULL) */ +static struct qdisc_util *qdisc_list; +static struct filter_util *filter_list; #ifdef ANDROID extern struct qdisc_util cbq_qdisc_util; @@ -64,7 +63,7 @@ static int print_noqopt(struct qdisc_util *qu, FILE *f, { if (opt && RTA_PAYLOAD(opt)) fprintf(f, "[Unknown qdisc, optlen=%u] ", - (unsigned) RTA_PAYLOAD(opt)); + (unsigned int) RTA_PAYLOAD(opt)); return 0; } @@ -81,7 +80,7 @@ static int print_nofopt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u { if (opt && RTA_PAYLOAD(opt)) fprintf(f, "fh %08x [Unknown filter, optlen=%u] ", - fhandle, (unsigned) RTA_PAYLOAD(opt)); + fhandle, (unsigned int) RTA_PAYLOAD(opt)); else if (fhandle) fprintf(f, "fh %08x ", fhandle); return 0; @@ -97,6 +96,7 @@ static int parse_nofopt(struct filter_util *qu, char *fhandle, int argc, char ** } if (fhandle) { struct tcmsg *t = NLMSG_DATA(n); + if (get_u32(&handle, fhandle, 16)) { fprintf(stderr, "Unparsable filter ID \"%s\"\n", fhandle); return -1; @@ -151,11 +151,9 @@ reg: return q; noexist: - q = malloc(sizeof(*q)); + q = calloc(1, sizeof(*q)); if (q) { - - memset(q, 0, sizeof(*q)); - q->id = strcpy(malloc(strlen(str)+1), str); + q->id = strdup(str); q->parse_qopt = parse_noqopt; q->print_qopt = print_noqopt; goto reg; @@ -203,9 +201,8 @@ reg: filter_list = q; return q; noexist: - q = malloc(sizeof(*q)); + q = calloc(1, sizeof(*q)); if (q) { - memset(q, 0, sizeof(*q)); strncpy(q->id, str, 15); q->parse_fopt = parse_nofopt; q->print_fopt = print_nofopt; @@ -222,9 +219,8 @@ static void usage(void) #else " tc [-force] -batch filename\n" #endif - "where OBJECT := { qdisc | class | filter | action | monitor | exec }\n" - " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | " - "-n[etns] name |\n" + "where OBJECT := { qdisc | class | filter | action | monitor | exec }\n" + " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | -n[etns] name |\n" " -nm | -nam[es] | { -cf | -conf } path }\n"); } diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c deleted file mode 100644 index 42c88418..00000000 --- a/tc/tc_bpf.c +++ /dev/null @@ -1,1892 +0,0 @@ -/* - * tc_bpf.c BPF common code - * - * This program is free software; you can distribute 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: Daniel Borkmann <dborkman@redhat.com> - * Jiri Pirko <jiri@resnulli.us> - * Alexei Starovoitov <ast@plumgrid.com> - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdbool.h> -#include <stdint.h> -#include <errno.h> -#include <fcntl.h> -#include <stdarg.h> - -#ifdef HAVE_ELF -#include <libelf.h> -#include <gelf.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <sys/vfs.h> -#include <sys/mount.h> -#include <sys/syscall.h> -#include <sys/sendfile.h> -#include <sys/resource.h> - -#include <linux/bpf.h> -#include <linux/filter.h> -#include <linux/if_alg.h> - -#include <arpa/inet.h> - -#include "utils.h" - -#include "bpf_elf.h" -#include "bpf_scm.h" - -#include "tc_util.h" -#include "tc_bpf.h" - -#ifdef HAVE_ELF -static int bpf_obj_open(const char *path, enum bpf_prog_type type, - const char *sec, bool verbose); -#else -static int bpf_obj_open(const char *path, enum bpf_prog_type type, - const char *sec, bool verbose) -{ - fprintf(stderr, "No ELF library support compiled in.\n"); - errno = ENOSYS; - return -1; -} -#endif - -static inline __u64 bpf_ptr_to_u64(const void *ptr) -{ - return (__u64)(unsigned long)ptr; -} - -static int bpf(int cmd, union bpf_attr *attr, unsigned int size) -{ -#ifdef __NR_bpf - return syscall(__NR_bpf, cmd, attr, size); -#else - fprintf(stderr, "No bpf syscall, kernel headers too old?\n"); - errno = ENOSYS; - return -1; -#endif -} - -static int bpf_map_update(int fd, const void *key, const void *value, - uint64_t flags) -{ - union bpf_attr attr = { - .map_fd = fd, - .key = bpf_ptr_to_u64(key), - .value = bpf_ptr_to_u64(value), - .flags = flags, - }; - - return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); -} - -static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, - char **bpf_string, bool *need_release, - const char separator) -{ - char sp; - - if (from_file) { - size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,"); - char *tmp_string; - FILE *fp; - - tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len; - tmp_string = malloc(tmp_len); - if (tmp_string == NULL) - return -ENOMEM; - - memset(tmp_string, 0, tmp_len); - - fp = fopen(arg, "r"); - if (fp == NULL) { - perror("Cannot fopen"); - free(tmp_string); - return -ENOENT; - } - - if (!fgets(tmp_string, tmp_len, fp)) { - free(tmp_string); - fclose(fp); - return -EIO; - } - - fclose(fp); - - *need_release = true; - *bpf_string = tmp_string; - } else { - *need_release = false; - *bpf_string = arg; - } - - if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 || - sp != separator) { - if (*need_release) - free(*bpf_string); - return -EINVAL; - } - - return 0; -} - -static int bpf_ops_parse(int argc, char **argv, struct sock_filter *bpf_ops, - bool from_file) -{ - char *bpf_string, *token, separator = ','; - int ret = 0, i = 0; - bool need_release; - __u16 bpf_len = 0; - - if (argc < 1) - return -EINVAL; - if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string, - &need_release, separator)) - return -EINVAL; - if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) { - ret = -EINVAL; - goto out; - } - - token = bpf_string; - while ((token = strchr(token, separator)) && (++token)[0]) { - if (i >= bpf_len) { - fprintf(stderr, "Real program length exceeds encoded " - "length parameter!\n"); - ret = -EINVAL; - goto out; - } - - if (sscanf(token, "%hu %hhu %hhu %u,", - &bpf_ops[i].code, &bpf_ops[i].jt, - &bpf_ops[i].jf, &bpf_ops[i].k) != 4) { - fprintf(stderr, "Error at instruction %d!\n", i); - ret = -EINVAL; - goto out; - } - - i++; - } - - if (i != bpf_len) { - fprintf(stderr, "Parsed program length is less than encoded" - "length parameter!\n"); - ret = -EINVAL; - goto out; - } - ret = bpf_len; -out: - if (need_release) - free(bpf_string); - - return ret; -} - -void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) -{ - struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops); - int i; - - if (len == 0) - return; - - fprintf(f, "bytecode \'%u,", len); - - for (i = 0; i < len - 1; i++) - fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt, - ops[i].jf, ops[i].k); - - fprintf(f, "%hu %hhu %hhu %u\'", ops[i].code, ops[i].jt, - ops[i].jf, ops[i].k); -} - -static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, - int length) -{ - char file[PATH_MAX], buff[4096]; - struct bpf_elf_map tmp, zero; - unsigned int val; - FILE *fp; - - snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd); - - fp = fopen(file, "r"); - if (!fp) { - fprintf(stderr, "No procfs support?!\n"); - return -EIO; - } - - memset(&tmp, 0, sizeof(tmp)); - while (fgets(buff, sizeof(buff), fp)) { - if (sscanf(buff, "map_type:\t%u", &val) == 1) - tmp.type = val; - else if (sscanf(buff, "key_size:\t%u", &val) == 1) - tmp.size_key = val; - else if (sscanf(buff, "value_size:\t%u", &val) == 1) - tmp.size_value = val; - else if (sscanf(buff, "max_entries:\t%u", &val) == 1) - tmp.max_elem = val; - } - - fclose(fp); - - if (!memcmp(&tmp, map, length)) { - return 0; - } else { - memset(&zero, 0, sizeof(zero)); - /* If kernel doesn't have eBPF-related fdinfo, we cannot do much, - * so just accept it. We know we do have an eBPF fd and in this - * case, everything is 0. It is guaranteed that no such map exists - * since map type of 0 is unloadable BPF_MAP_TYPE_UNSPEC. - */ - if (!memcmp(&tmp, &zero, length)) - return 0; - - fprintf(stderr, "Map specs from pinned file differ!\n"); - return -EINVAL; - } -} - -static int bpf_mnt_fs(const char *target) -{ - bool bind_done = false; - - while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) { - if (errno != EINVAL || bind_done) { - fprintf(stderr, "mount --make-private %s failed: %s\n", - target, strerror(errno)); - return -1; - } - - if (mount(target, target, "none", MS_BIND, NULL)) { - fprintf(stderr, "mount --bind %s %s failed: %s\n", - target, target, strerror(errno)); - return -1; - } - - bind_done = true; - } - - if (mount("bpf", target, "bpf", 0, NULL)) { - fprintf(stderr, "mount -t bpf bpf %s failed: %s\n", - target, strerror(errno)); - return -1; - } - - return 0; -} - -static int bpf_valid_mntpt(const char *mnt, unsigned long magic) -{ - struct statfs st_fs; - - if (statfs(mnt, &st_fs) < 0) - return -ENOENT; - if ((unsigned long)st_fs.f_type != magic) - return -ENOENT; - - return 0; -} - -static const char *bpf_find_mntpt(const char *fstype, unsigned long magic, - char *mnt, int len, - const char * const *known_mnts) -{ - const char * const *ptr; - char type[100]; - FILE *fp; - - if (known_mnts) { - ptr = known_mnts; - while (*ptr) { - if (bpf_valid_mntpt(*ptr, magic) == 0) { - strncpy(mnt, *ptr, len - 1); - mnt[len - 1] = 0; - return mnt; - } - ptr++; - } - } - - fp = fopen("/proc/mounts", "r"); - if (fp == NULL || len != PATH_MAX) - return NULL; - - while (fscanf(fp, "%*s %" textify(PATH_MAX) "s %99s %*s %*d %*d\n", - mnt, type) == 2) { - if (strcmp(type, fstype) == 0) - break; - } - - fclose(fp); - if (strcmp(type, fstype) != 0) - return NULL; - - return mnt; -} - -int bpf_trace_pipe(void) -{ - char tracefs_mnt[PATH_MAX] = TRACE_DIR_MNT; - static const char * const tracefs_known_mnts[] = { - TRACE_DIR_MNT, - "/sys/kernel/debug/tracing", - "/tracing", - "/trace", - 0, - }; - char tpipe[PATH_MAX]; - const char *mnt; - int fd; - - mnt = bpf_find_mntpt("tracefs", TRACEFS_MAGIC, tracefs_mnt, - sizeof(tracefs_mnt), tracefs_known_mnts); - if (!mnt) { - fprintf(stderr, "tracefs not mounted?\n"); - return -1; - } - - snprintf(tpipe, sizeof(tpipe), "%s/trace_pipe", mnt); - - fd = open(tpipe, O_RDONLY); - if (fd < 0) - return -1; - - fprintf(stderr, "Running! Hang up with ^C!\n\n"); - while (1) { - static char buff[4096]; - ssize_t ret; - - ret = read(fd, buff, sizeof(buff) - 1); - if (ret > 0) { - write(2, buff, ret); - fflush(stderr); - } - } - - return 0; -} - -static const char *bpf_get_tc_dir(void) -{ - static bool bpf_mnt_cached = false; - static char bpf_tc_dir[PATH_MAX]; - static const char *mnt; - static const char * const bpf_known_mnts[] = { - BPF_DIR_MNT, - 0, - }; - char bpf_mnt[PATH_MAX] = BPF_DIR_MNT; - char bpf_glo_dir[PATH_MAX]; - int ret; - - if (bpf_mnt_cached) - goto done; - - mnt = bpf_find_mntpt("bpf", BPF_FS_MAGIC, bpf_mnt, sizeof(bpf_mnt), - bpf_known_mnts); - if (!mnt) { - mnt = getenv(BPF_ENV_MNT); - if (!mnt) - mnt = BPF_DIR_MNT; - ret = bpf_mnt_fs(mnt); - if (ret) { - mnt = NULL; - goto out; - } - } - - snprintf(bpf_tc_dir, sizeof(bpf_tc_dir), "%s/%s", mnt, BPF_DIR_TC); - ret = mkdir(bpf_tc_dir, S_IRWXU); - if (ret && errno != EEXIST) { - fprintf(stderr, "mkdir %s failed: %s\n", bpf_tc_dir, - strerror(errno)); - mnt = NULL; - goto out; - } - - snprintf(bpf_glo_dir, sizeof(bpf_glo_dir), "%s/%s", - bpf_tc_dir, BPF_DIR_GLOBALS); - ret = mkdir(bpf_glo_dir, S_IRWXU); - if (ret && errno != EEXIST) { - fprintf(stderr, "mkdir %s failed: %s\n", bpf_glo_dir, - strerror(errno)); - mnt = NULL; - goto out; - } - - mnt = bpf_tc_dir; -out: - bpf_mnt_cached = true; -done: - return mnt; -} - -static int bpf_obj_get(const char *pathname) -{ - union bpf_attr attr; - char tmp[PATH_MAX]; - - if (strlen(pathname) > 2 && pathname[0] == 'm' && - pathname[1] == ':' && bpf_get_tc_dir()) { - snprintf(tmp, sizeof(tmp), "%s/%s", - bpf_get_tc_dir(), pathname + 2); - pathname = tmp; - } - - memset(&attr, 0, sizeof(attr)); - attr.pathname = bpf_ptr_to_u64(pathname); - - return bpf(BPF_OBJ_GET, &attr, sizeof(attr)); -} - -const char *bpf_default_section(const enum bpf_prog_type type) -{ - switch (type) { - case BPF_PROG_TYPE_SCHED_CLS: - return ELF_SECTION_CLASSIFIER; - case BPF_PROG_TYPE_SCHED_ACT: - return ELF_SECTION_ACTION; - default: - return NULL; - } -} - -enum bpf_mode { - CBPF_BYTECODE = 0, - CBPF_FILE, - EBPF_OBJECT, - EBPF_PINNED, - __BPF_MODE_MAX, -#define BPF_MODE_MAX __BPF_MODE_MAX -}; - -static int bpf_parse(int *ptr_argc, char ***ptr_argv, const bool *opt_tbl, - enum bpf_prog_type *type, enum bpf_mode *mode, - const char **ptr_object, const char **ptr_section, - const char **ptr_uds_name, struct sock_filter *opcodes) -{ - const char *file, *section, *uds_name; - bool verbose = false; - int ret, argc; - char **argv; - - argv = *ptr_argv; - argc = *ptr_argc; - - if (opt_tbl[CBPF_BYTECODE] && - (matches(*argv, "bytecode") == 0 || - strcmp(*argv, "bc") == 0)) { - *mode = CBPF_BYTECODE; - } else if (opt_tbl[CBPF_FILE] && - (matches(*argv, "bytecode-file") == 0 || - strcmp(*argv, "bcf") == 0)) { - *mode = CBPF_FILE; - } else if (opt_tbl[EBPF_OBJECT] && - (matches(*argv, "object-file") == 0 || - strcmp(*argv, "obj") == 0)) { - *mode = EBPF_OBJECT; - } else if (opt_tbl[EBPF_PINNED] && - (matches(*argv, "object-pinned") == 0 || - matches(*argv, "pinned") == 0 || - matches(*argv, "fd") == 0)) { - *mode = EBPF_PINNED; - } else { - fprintf(stderr, "What mode is \"%s\"?\n", *argv); - return -1; - } - - NEXT_ARG(); - file = section = uds_name = NULL; - if (*mode == EBPF_OBJECT || *mode == EBPF_PINNED) { - file = *argv; - NEXT_ARG_FWD(); - - if (*type == BPF_PROG_TYPE_UNSPEC) { - if (argc > 0 && matches(*argv, "type") == 0) { - NEXT_ARG(); - if (matches(*argv, "cls") == 0) { - *type = BPF_PROG_TYPE_SCHED_CLS; - } else if (matches(*argv, "act") == 0) { - *type = BPF_PROG_TYPE_SCHED_ACT; - } else { - fprintf(stderr, "What type is \"%s\"?\n", - *argv); - return -1; - } - NEXT_ARG_FWD(); - } else { - *type = BPF_PROG_TYPE_SCHED_CLS; - } - } - - section = bpf_default_section(*type); - if (argc > 0 && matches(*argv, "section") == 0) { - NEXT_ARG(); - section = *argv; - NEXT_ARG_FWD(); - } - - uds_name = getenv(BPF_ENV_UDS); - if (argc > 0 && !uds_name && - matches(*argv, "export") == 0) { - NEXT_ARG(); - uds_name = *argv; - NEXT_ARG_FWD(); - } - - if (argc > 0 && matches(*argv, "verbose") == 0) { - verbose = true; - NEXT_ARG_FWD(); - } - - PREV_ARG(); - } - - if (*mode == CBPF_BYTECODE || *mode == CBPF_FILE) - ret = bpf_ops_parse(argc, argv, opcodes, *mode == CBPF_FILE); - else if (*mode == EBPF_OBJECT) - ret = bpf_obj_open(file, *type, section, verbose); - else if (*mode == EBPF_PINNED) - ret = bpf_obj_get(file); - else - return -1; - - if (ptr_object) - *ptr_object = file; - if (ptr_section) - *ptr_section = section; - if (ptr_uds_name) - *ptr_uds_name = uds_name; - - *ptr_argc = argc; - *ptr_argv = argv; - - return ret; -} - -int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, - enum bpf_prog_type type, const char **ptr_object, - const char **ptr_uds_name, struct nlmsghdr *n) -{ - struct sock_filter opcodes[BPF_MAXINSNS]; - const bool opt_tbl[BPF_MODE_MAX] = { - [CBPF_BYTECODE] = true, - [CBPF_FILE] = true, - [EBPF_OBJECT] = true, - [EBPF_PINNED] = true, - }; - char annotation[256]; - const char *section; - enum bpf_mode mode; - int ret; - - ret = bpf_parse(ptr_argc, ptr_argv, opt_tbl, &type, &mode, - ptr_object, §ion, ptr_uds_name, opcodes); - if (ret < 0) - return ret; - - if (mode == CBPF_BYTECODE || mode == CBPF_FILE) { - addattr16(n, MAX_MSG, nla_tbl[BPF_NLA_OPS_LEN], ret); - addattr_l(n, MAX_MSG, nla_tbl[BPF_NLA_OPS], opcodes, - ret * sizeof(struct sock_filter)); - } - - if (mode == EBPF_OBJECT || mode == EBPF_PINNED) { - snprintf(annotation, sizeof(annotation), "%s:[%s]", - basename(*ptr_object), mode == EBPF_PINNED ? - "*fsobj" : section); - - addattr32(n, MAX_MSG, nla_tbl[BPF_NLA_FD], ret); - addattrstrz(n, MAX_MSG, nla_tbl[BPF_NLA_NAME], annotation); - } - - return 0; -} - -int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) -{ - enum bpf_prog_type type = BPF_PROG_TYPE_UNSPEC; - const bool opt_tbl[BPF_MODE_MAX] = { - [CBPF_BYTECODE] = false, - [CBPF_FILE] = false, - [EBPF_OBJECT] = true, - [EBPF_PINNED] = true, - }; - const struct bpf_elf_map test = { - .type = BPF_MAP_TYPE_PROG_ARRAY, - .size_key = sizeof(int), - .size_value = sizeof(int), - }; - int ret, prog_fd, map_fd; - const char *section; - enum bpf_mode mode; - uint32_t map_key; - - prog_fd = bpf_parse(&argc, &argv, opt_tbl, &type, &mode, - NULL, §ion, NULL, NULL); - if (prog_fd < 0) - return prog_fd; - if (key) { - map_key = *key; - } else { - ret = sscanf(section, "%*i/%i", &map_key); - if (ret != 1) { - fprintf(stderr, "Couldn\'t infer map key from section " - "name! Please provide \'key\' argument!\n"); - ret = -EINVAL; - goto out_prog; - } - } - - map_fd = bpf_obj_get(map_path); - if (map_fd < 0) { - fprintf(stderr, "Couldn\'t retrieve pinned map \'%s\': %s\n", - map_path, strerror(errno)); - ret = map_fd; - goto out_prog; - } - - ret = bpf_map_selfcheck_pinned(map_fd, &test, - offsetof(struct bpf_elf_map, max_elem)); - if (ret < 0) { - fprintf(stderr, "Map \'%s\' self-check failed!\n", map_path); - goto out_map; - } - - ret = bpf_map_update(map_fd, &map_key, &prog_fd, BPF_ANY); - if (ret < 0) - fprintf(stderr, "Map update failed: %s\n", strerror(errno)); -out_map: - close(map_fd); -out_prog: - close(prog_fd); - return ret; -} - -#ifdef HAVE_ELF -struct bpf_elf_prog { - enum bpf_prog_type type; - const struct bpf_insn *insns; - size_t size; - const char *license; -}; - -struct bpf_hash_entry { - unsigned int pinning; - const char *subpath; - struct bpf_hash_entry *next; -}; - -struct bpf_elf_ctx { - Elf *elf_fd; - GElf_Ehdr elf_hdr; - Elf_Data *sym_tab; - Elf_Data *str_tab; - int obj_fd; - int map_fds[ELF_MAX_MAPS]; - struct bpf_elf_map maps[ELF_MAX_MAPS]; - int sym_num; - int map_num; - bool *sec_done; - int sec_maps; - char license[ELF_MAX_LICENSE_LEN]; - enum bpf_prog_type type; - bool verbose; - struct bpf_elf_st stat; - struct bpf_hash_entry *ht[256]; -}; - -struct bpf_elf_sec_data { - GElf_Shdr sec_hdr; - Elf_Data *sec_data; - const char *sec_name; -}; - -struct bpf_map_data { - int *fds; - const char *obj; - struct bpf_elf_st *st; - struct bpf_elf_map *ent; -}; - -/* If we provide a small buffer with log level enabled, the kernel - * could fail program load as no buffer space is available for the - * log and thus verifier fails. In case something doesn't pass the - * verifier we still want to hand something descriptive to the user. - */ -static char bpf_log_buf[65536]; - -static __check_format_string(1, 2) void bpf_dump_error(const char *format, ...) -{ - va_list vl; - - va_start(vl, format); - vfprintf(stderr, format, vl); - va_end(vl); - - if (bpf_log_buf[0]) { - fprintf(stderr, "%s\n", bpf_log_buf); - memset(bpf_log_buf, 0, sizeof(bpf_log_buf)); - } -} - -static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, - unsigned int size_value, unsigned int max_elem) -{ - union bpf_attr attr = { - .map_type = type, - .key_size = size_key, - .value_size = size_value, - .max_entries = max_elem, - }; - - return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); -} - -static int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, - size_t size, const char *license) -{ - union bpf_attr attr = { - .prog_type = type, - .insns = bpf_ptr_to_u64(insns), - .insn_cnt = size / sizeof(struct bpf_insn), - .license = bpf_ptr_to_u64(license), - .log_buf = bpf_ptr_to_u64(bpf_log_buf), - .log_size = sizeof(bpf_log_buf), - .log_level = 1, - }; - - if (getenv(BPF_ENV_NOLOG)) { - attr.log_buf = 0; - attr.log_size = 0; - attr.log_level = 0; - } - - return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); -} - -static int bpf_obj_pin(int fd, const char *pathname) -{ - union bpf_attr attr = { - .pathname = bpf_ptr_to_u64(pathname), - .bpf_fd = fd, - }; - - return bpf(BPF_OBJ_PIN, &attr, sizeof(attr)); -} - -static int bpf_obj_hash(const char *object, uint8_t *out, size_t len) -{ - struct sockaddr_alg alg = { - .salg_family = AF_ALG, - .salg_type = "hash", - .salg_name = "sha1", - }; - int ret, cfd, ofd, ffd; - struct stat stbuff; - ssize_t size; - - if (!object || len != 20) - return -EINVAL; - - cfd = socket(AF_ALG, SOCK_SEQPACKET, 0); - if (cfd < 0) { - fprintf(stderr, "Cannot get AF_ALG socket: %s\n", - strerror(errno)); - return cfd; - } - - ret = bind(cfd, (struct sockaddr *)&alg, sizeof(alg)); - if (ret < 0) { - fprintf(stderr, "Error binding socket: %s\n", strerror(errno)); - goto out_cfd; - } - - ofd = accept(cfd, NULL, 0); - if (ofd < 0) { - fprintf(stderr, "Error accepting socket: %s\n", - strerror(errno)); - ret = ofd; - goto out_cfd; - } - - ffd = open(object, O_RDONLY); - if (ffd < 0) { - fprintf(stderr, "Error opening object %s: %s\n", - object, strerror(errno)); - ret = ffd; - goto out_ofd; - } - - ret = fstat(ffd, &stbuff); - if (ret < 0) { - fprintf(stderr, "Error doing fstat: %s\n", - strerror(errno)); - goto out_ffd; - } - - size = sendfile(ofd, ffd, NULL, stbuff.st_size); - if (size != stbuff.st_size) { - fprintf(stderr, "Error from sendfile (%zd vs %zu bytes): %s\n", - size, stbuff.st_size, strerror(errno)); - ret = -1; - goto out_ffd; - } - - size = read(ofd, out, len); - if (size != len) { - fprintf(stderr, "Error from read (%zd vs %zu bytes): %s\n", - size, len, strerror(errno)); - ret = -1; - } else { - ret = 0; - } -out_ffd: - close(ffd); -out_ofd: - close(ofd); -out_cfd: - close(cfd); - return ret; -} - -static const char *bpf_get_obj_uid(const char *pathname) -{ - static bool bpf_uid_cached = false; - static char bpf_uid[64]; - uint8_t tmp[20]; - int ret; - - if (bpf_uid_cached) - goto done; - - ret = bpf_obj_hash(pathname, tmp, sizeof(tmp)); - if (ret) { - fprintf(stderr, "Object hashing failed!\n"); - return NULL; - } - - hexstring_n2a(tmp, sizeof(tmp), bpf_uid, sizeof(bpf_uid)); - bpf_uid_cached = true; -done: - return bpf_uid; -} - -static int bpf_init_env(const char *pathname) -{ - struct rlimit limit = { - .rlim_cur = RLIM_INFINITY, - .rlim_max = RLIM_INFINITY, - }; - - /* Don't bother in case we fail! */ - setrlimit(RLIMIT_MEMLOCK, &limit); - - if (!bpf_get_tc_dir()) { - fprintf(stderr, "Continuing without mounted eBPF fs. " - "Too old kernel?\n"); - return 0; - } - - if (!bpf_get_obj_uid(pathname)) - return -1; - - return 0; -} - -static const char *bpf_custom_pinning(const struct bpf_elf_ctx *ctx, - uint32_t pinning) -{ - struct bpf_hash_entry *entry; - - entry = ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)]; - while (entry && entry->pinning != pinning) - entry = entry->next; - - return entry ? entry->subpath : NULL; -} - -static bool bpf_no_pinning(const struct bpf_elf_ctx *ctx, - uint32_t pinning) -{ - switch (pinning) { - case PIN_OBJECT_NS: - case PIN_GLOBAL_NS: - return false; - case PIN_NONE: - return true; - default: - return !bpf_custom_pinning(ctx, pinning); - } -} - -static void bpf_make_pathname(char *pathname, size_t len, const char *name, - const struct bpf_elf_ctx *ctx, uint32_t pinning) -{ - switch (pinning) { - case PIN_OBJECT_NS: - snprintf(pathname, len, "%s/%s/%s", bpf_get_tc_dir(), - bpf_get_obj_uid(NULL), name); - break; - case PIN_GLOBAL_NS: - snprintf(pathname, len, "%s/%s/%s", bpf_get_tc_dir(), - BPF_DIR_GLOBALS, name); - break; - default: - snprintf(pathname, len, "%s/../%s/%s", bpf_get_tc_dir(), - bpf_custom_pinning(ctx, pinning), name); - break; - } -} - -static int bpf_probe_pinned(const char *name, const struct bpf_elf_ctx *ctx, - uint32_t pinning) -{ - char pathname[PATH_MAX]; - - if (bpf_no_pinning(ctx, pinning) || !bpf_get_tc_dir()) - return 0; - - bpf_make_pathname(pathname, sizeof(pathname), name, ctx, pinning); - return bpf_obj_get(pathname); -} - -static int bpf_make_obj_path(void) -{ - char tmp[PATH_MAX]; - int ret; - - snprintf(tmp, sizeof(tmp), "%s/%s", bpf_get_tc_dir(), - bpf_get_obj_uid(NULL)); - - ret = mkdir(tmp, S_IRWXU); - if (ret && errno != EEXIST) { - fprintf(stderr, "mkdir %s failed: %s\n", tmp, strerror(errno)); - return ret; - } - - return 0; -} - -static int bpf_make_custom_path(const char *todo) -{ - char tmp[PATH_MAX], rem[PATH_MAX], *sub; - int ret; - - snprintf(tmp, sizeof(tmp), "%s/../", bpf_get_tc_dir()); - snprintf(rem, sizeof(rem), "%s/", todo); - sub = strtok(rem, "/"); - - while (sub) { - if (strlen(tmp) + strlen(sub) + 2 > PATH_MAX) - return -EINVAL; - - strcat(tmp, sub); - strcat(tmp, "/"); - - ret = mkdir(tmp, S_IRWXU); - if (ret && errno != EEXIST) { - fprintf(stderr, "mkdir %s failed: %s\n", tmp, - strerror(errno)); - return ret; - } - - sub = strtok(NULL, "/"); - } - - return 0; -} - -static int bpf_place_pinned(int fd, const char *name, - const struct bpf_elf_ctx *ctx, uint32_t pinning) -{ - char pathname[PATH_MAX]; - const char *tmp; - int ret = 0; - - if (bpf_no_pinning(ctx, pinning) || !bpf_get_tc_dir()) - return 0; - - if (pinning == PIN_OBJECT_NS) - ret = bpf_make_obj_path(); - else if ((tmp = bpf_custom_pinning(ctx, pinning))) - ret = bpf_make_custom_path(tmp); - if (ret < 0) - return ret; - - bpf_make_pathname(pathname, sizeof(pathname), name, ctx, pinning); - return bpf_obj_pin(fd, pathname); -} - -static int bpf_prog_attach(const char *section, - const struct bpf_elf_prog *prog, bool verbose) -{ - int fd; - - /* We can add pinning here later as well, same as bpf_map_attach(). */ - errno = 0; - fd = bpf_prog_load(prog->type, prog->insns, prog->size, - prog->license); - if (fd < 0 || verbose) { - bpf_dump_error("Prog section \'%s\' (type:%u insns:%zu " - "license:\'%s\') %s%s (%d)!\n\n", - section, prog->type, - prog->size / sizeof(struct bpf_insn), - prog->license, fd < 0 ? "rejected: " : - "loaded", fd < 0 ? strerror(errno) : "", - fd < 0 ? errno : fd); - } - - return fd; -} - -static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, - const struct bpf_elf_ctx *ctx, bool verbose) -{ - int fd, ret; - - fd = bpf_probe_pinned(name, ctx, map->pinning); - if (fd > 0) { - ret = bpf_map_selfcheck_pinned(fd, map, - offsetof(struct bpf_elf_map, - id)); - if (ret < 0) { - close(fd); - fprintf(stderr, "Map \'%s\' self-check failed!\n", - name); - return ret; - } - if (verbose) - fprintf(stderr, "Map \'%s\' loaded as pinned!\n", - name); - return fd; - } - - errno = 0; - fd = bpf_map_create(map->type, map->size_key, map->size_value, - map->max_elem); - if (fd < 0 || verbose) { - bpf_dump_error("Map \'%s\' (type:%u id:%u pinning:%u " - "ksize:%u vsize:%u max-elems:%u) %s%s (%d)!\n", - name, map->type, map->id, map->pinning, - map->size_key, map->size_value, map->max_elem, - fd < 0 ? "rejected: " : "loaded", fd < 0 ? - strerror(errno) : "", fd < 0 ? errno : fd); - if (fd < 0) - return fd; - } - - ret = bpf_place_pinned(fd, name, ctx, map->pinning); - if (ret < 0 && errno != EEXIST) { - fprintf(stderr, "Could not pin %s map: %s\n", name, - strerror(errno)); - close(fd); - return ret; - } - - return fd; -} - -#define __ELF_ST_BIND(x) ((x) >> 4) -#define __ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) - -static const char *bpf_str_tab_name(const struct bpf_elf_ctx *ctx, - const GElf_Sym *sym) -{ - return ctx->str_tab->d_buf + sym->st_name; -} - -static const char *bpf_map_fetch_name(struct bpf_elf_ctx *ctx, int which) -{ - GElf_Sym sym; - int i; - - for (i = 0; i < ctx->sym_num; i++) { - if (gelf_getsym(ctx->sym_tab, i, &sym) != &sym) - continue; - - if (__ELF_ST_BIND(sym.st_info) != STB_GLOBAL || - __ELF_ST_TYPE(sym.st_info) != STT_NOTYPE || - sym.st_shndx != ctx->sec_maps || - sym.st_value / sizeof(struct bpf_elf_map) != which) - continue; - - return bpf_str_tab_name(ctx, &sym); - } - - return NULL; -} - -static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx) -{ - const char *map_name; - int i, fd; - - for (i = 0; i < ctx->map_num; i++) { - map_name = bpf_map_fetch_name(ctx, i); - if (!map_name) - return -EIO; - - fd = bpf_map_attach(map_name, &ctx->maps[i], ctx, - ctx->verbose); - if (fd < 0) - return fd; - - ctx->map_fds[i] = fd; - } - - return 0; -} - -static int bpf_fill_section_data(struct bpf_elf_ctx *ctx, int section, - struct bpf_elf_sec_data *data) -{ - Elf_Data *sec_edata; - GElf_Shdr sec_hdr; - Elf_Scn *sec_fd; - char *sec_name; - - memset(data, 0, sizeof(*data)); - - sec_fd = elf_getscn(ctx->elf_fd, section); - if (!sec_fd) - return -EINVAL; - if (gelf_getshdr(sec_fd, &sec_hdr) != &sec_hdr) - return -EIO; - - sec_name = elf_strptr(ctx->elf_fd, ctx->elf_hdr.e_shstrndx, - sec_hdr.sh_name); - if (!sec_name || !sec_hdr.sh_size) - return -ENOENT; - - sec_edata = elf_getdata(sec_fd, NULL); - if (!sec_edata || elf_getdata(sec_fd, sec_edata)) - return -EIO; - - memcpy(&data->sec_hdr, &sec_hdr, sizeof(sec_hdr)); - - data->sec_name = sec_name; - data->sec_data = sec_edata; - return 0; -} - -static int bpf_fetch_maps(struct bpf_elf_ctx *ctx, int section, - struct bpf_elf_sec_data *data) -{ - if (data->sec_data->d_size % sizeof(struct bpf_elf_map) != 0) - return -EINVAL; - - ctx->map_num = data->sec_data->d_size / sizeof(struct bpf_elf_map); - ctx->sec_maps = section; - ctx->sec_done[section] = true; - - if (ctx->map_num > ARRAY_SIZE(ctx->map_fds)) { - fprintf(stderr, "Too many BPF maps in ELF section!\n"); - return -ENOMEM; - } - - memcpy(ctx->maps, data->sec_data->d_buf, data->sec_data->d_size); - return 0; -} - -static int bpf_fetch_license(struct bpf_elf_ctx *ctx, int section, - struct bpf_elf_sec_data *data) -{ - if (data->sec_data->d_size > sizeof(ctx->license)) - return -ENOMEM; - - memcpy(ctx->license, data->sec_data->d_buf, data->sec_data->d_size); - ctx->sec_done[section] = true; - return 0; -} - -static int bpf_fetch_symtab(struct bpf_elf_ctx *ctx, int section, - struct bpf_elf_sec_data *data) -{ - ctx->sym_tab = data->sec_data; - ctx->sym_num = data->sec_hdr.sh_size / data->sec_hdr.sh_entsize; - ctx->sec_done[section] = true; - return 0; -} - -static int bpf_fetch_strtab(struct bpf_elf_ctx *ctx, int section, - struct bpf_elf_sec_data *data) -{ - ctx->str_tab = data->sec_data; - ctx->sec_done[section] = true; - return 0; -} - -static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx) -{ - struct bpf_elf_sec_data data; - int i, ret = -1; - - for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { - ret = bpf_fill_section_data(ctx, i, &data); - if (ret < 0) - continue; - - if (data.sec_hdr.sh_type == SHT_PROGBITS && - !strcmp(data.sec_name, ELF_SECTION_MAPS)) - ret = bpf_fetch_maps(ctx, i, &data); - else if (data.sec_hdr.sh_type == SHT_PROGBITS && - !strcmp(data.sec_name, ELF_SECTION_LICENSE)) - ret = bpf_fetch_license(ctx, i, &data); - else if (data.sec_hdr.sh_type == SHT_SYMTAB && - !strcmp(data.sec_name, ".symtab")) - ret = bpf_fetch_symtab(ctx, i, &data); - else if (data.sec_hdr.sh_type == SHT_STRTAB && - !strcmp(data.sec_name, ".strtab")) - ret = bpf_fetch_strtab(ctx, i, &data); - if (ret < 0) { - fprintf(stderr, "Error parsing section %d! Perhaps" - "check with readelf -a?\n", i); - break; - } - } - - if (ctx->sym_tab && ctx->str_tab && ctx->sec_maps) { - ret = bpf_maps_attach_all(ctx); - if (ret < 0) { - fprintf(stderr, "Error loading maps into kernel!\n"); - return ret; - } - } - - return ret; -} - -static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section) -{ - struct bpf_elf_sec_data data; - struct bpf_elf_prog prog; - int ret, i, fd = -1; - - for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { - if (ctx->sec_done[i]) - continue; - - ret = bpf_fill_section_data(ctx, i, &data); - if (ret < 0 || - !(data.sec_hdr.sh_type == SHT_PROGBITS && - data.sec_hdr.sh_flags & SHF_EXECINSTR && - !strcmp(data.sec_name, section))) - continue; - - memset(&prog, 0, sizeof(prog)); - prog.type = ctx->type; - prog.insns = data.sec_data->d_buf; - prog.size = data.sec_data->d_size; - prog.license = ctx->license; - - fd = bpf_prog_attach(section, &prog, ctx->verbose); - if (fd < 0) - continue; - - ctx->sec_done[i] = true; - break; - } - - return fd; -} - -static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, - struct bpf_elf_sec_data *data_relo, - struct bpf_elf_sec_data *data_insn) -{ - Elf_Data *idata = data_insn->sec_data; - GElf_Shdr *rhdr = &data_relo->sec_hdr; - int relo_ent, relo_num = rhdr->sh_size / rhdr->sh_entsize; - struct bpf_insn *insns = idata->d_buf; - unsigned int num_insns = idata->d_size / sizeof(*insns); - - for (relo_ent = 0; relo_ent < relo_num; relo_ent++) { - unsigned int ioff, rmap; - GElf_Rel relo; - GElf_Sym sym; - - if (gelf_getrel(data_relo->sec_data, relo_ent, &relo) != &relo) - return -EIO; - - ioff = relo.r_offset / sizeof(struct bpf_insn); - if (ioff >= num_insns || - insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) - return -EINVAL; - - if (gelf_getsym(ctx->sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym) - return -EIO; - - rmap = sym.st_value / sizeof(struct bpf_elf_map); - if (rmap >= ARRAY_SIZE(ctx->map_fds)) - return -EINVAL; - if (!ctx->map_fds[rmap]) - return -EINVAL; - - if (ctx->verbose) - fprintf(stderr, "Map \'%s\' (%d) injected into prog " - "section \'%s\' at offset %u!\n", - bpf_str_tab_name(ctx, &sym), ctx->map_fds[rmap], - data_insn->sec_name, ioff); - - insns[ioff].src_reg = BPF_PSEUDO_MAP_FD; - insns[ioff].imm = ctx->map_fds[rmap]; - } - - return 0; -} - -static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) -{ - struct bpf_elf_sec_data data_relo, data_insn; - struct bpf_elf_prog prog; - int ret, idx, i, fd = -1; - - for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { - ret = bpf_fill_section_data(ctx, i, &data_relo); - if (ret < 0 || data_relo.sec_hdr.sh_type != SHT_REL) - continue; - - idx = data_relo.sec_hdr.sh_info; - ret = bpf_fill_section_data(ctx, idx, &data_insn); - if (ret < 0 || - !(data_insn.sec_hdr.sh_type == SHT_PROGBITS && - data_insn.sec_hdr.sh_flags & SHF_EXECINSTR && - !strcmp(data_insn.sec_name, section))) - continue; - - ret = bpf_apply_relo_data(ctx, &data_relo, &data_insn); - if (ret < 0) - continue; - - memset(&prog, 0, sizeof(prog)); - prog.type = ctx->type; - prog.insns = data_insn.sec_data->d_buf; - prog.size = data_insn.sec_data->d_size; - prog.license = ctx->license; - - fd = bpf_prog_attach(section, &prog, ctx->verbose); - if (fd < 0) - continue; - - ctx->sec_done[i] = true; - ctx->sec_done[idx] = true; - break; - } - - return fd; -} - -static int bpf_fetch_prog_sec(struct bpf_elf_ctx *ctx, const char *section) -{ - int ret = -1; - - if (ctx->sym_tab) - ret = bpf_fetch_prog_relo(ctx, section); - if (ret < 0) - ret = bpf_fetch_prog(ctx, section); - - return ret; -} - -static int bpf_find_map_by_id(struct bpf_elf_ctx *ctx, uint32_t id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++) - if (ctx->map_fds[i] && ctx->maps[i].id == id && - ctx->maps[i].type == BPF_MAP_TYPE_PROG_ARRAY) - return i; - return -1; -} - -static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx) -{ - struct bpf_elf_sec_data data; - uint32_t map_id, key_id; - int fd, i, ret, idx; - - for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { - if (ctx->sec_done[i]) - continue; - - ret = bpf_fill_section_data(ctx, i, &data); - if (ret < 0) - continue; - - ret = sscanf(data.sec_name, "%i/%i", &map_id, &key_id); - if (ret != 2) - continue; - - idx = bpf_find_map_by_id(ctx, map_id); - if (idx < 0) - continue; - - fd = bpf_fetch_prog_sec(ctx, data.sec_name); - if (fd < 0) - return -EIO; - - ret = bpf_map_update(ctx->map_fds[idx], &key_id, - &fd, BPF_ANY); - if (ret < 0) - return -ENOENT; - - ctx->sec_done[i] = true; - } - - return 0; -} - -static void bpf_save_finfo(struct bpf_elf_ctx *ctx) -{ - struct stat st; - int ret; - - memset(&ctx->stat, 0, sizeof(ctx->stat)); - - ret = fstat(ctx->obj_fd, &st); - if (ret < 0) { - fprintf(stderr, "Stat of elf file failed: %s\n", - strerror(errno)); - return; - } - - ctx->stat.st_dev = st.st_dev; - ctx->stat.st_ino = st.st_ino; -} - -static int bpf_read_pin_mapping(FILE *fp, uint32_t *id, char *path) -{ - char buff[PATH_MAX]; - - while (fgets(buff, sizeof(buff), fp)) { - char *ptr = buff; - - while (*ptr == ' ' || *ptr == '\t') - ptr++; - - if (*ptr == '#' || *ptr == '\n' || *ptr == 0) - continue; - - if (sscanf(ptr, "%i %s\n", id, path) != 2 && - sscanf(ptr, "%i %s #", id, path) != 2) { - strcpy(path, ptr); - return -1; - } - - return 1; - } - - return 0; -} - -static bool bpf_pinning_reserved(uint32_t pinning) -{ - switch (pinning) { - case PIN_NONE: - case PIN_OBJECT_NS: - case PIN_GLOBAL_NS: - return true; - default: - return false; - } -} - -static void bpf_hash_init(struct bpf_elf_ctx *ctx, const char *db_file) -{ - struct bpf_hash_entry *entry; - char subpath[PATH_MAX]; - uint32_t pinning; - FILE *fp; - int ret; - - fp = fopen(db_file, "r"); - if (!fp) - return; - - memset(subpath, 0, sizeof(subpath)); - while ((ret = bpf_read_pin_mapping(fp, &pinning, subpath))) { - if (ret == -1) { - fprintf(stderr, "Database %s is corrupted at: %s\n", - db_file, subpath); - fclose(fp); - return; - } - - if (bpf_pinning_reserved(pinning)) { - fprintf(stderr, "Database %s, id %u is reserved - " - "ignoring!\n", db_file, pinning); - continue; - } - - entry = malloc(sizeof(*entry)); - if (!entry) { - fprintf(stderr, "No memory left for db entry!\n"); - continue; - } - - entry->pinning = pinning; - entry->subpath = strdup(subpath); - if (!entry->subpath) { - fprintf(stderr, "No memory left for db entry!\n"); - free(entry); - continue; - } - - entry->next = ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)]; - ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)] = entry; - } - - fclose(fp); -} - -static void bpf_hash_destroy(struct bpf_elf_ctx *ctx) -{ - struct bpf_hash_entry *entry; - int i; - - for (i = 0; i < ARRAY_SIZE(ctx->ht); i++) { - while ((entry = ctx->ht[i]) != NULL) { - ctx->ht[i] = entry->next; - free((char *)entry->subpath); - free(entry); - } - } -} - -static int bpf_elf_check_ehdr(const struct bpf_elf_ctx *ctx) -{ - if (ctx->elf_hdr.e_type != ET_REL || - ctx->elf_hdr.e_machine != 0 || - ctx->elf_hdr.e_version != EV_CURRENT) { - fprintf(stderr, "ELF format error, ELF file not for eBPF?\n"); - return -EINVAL; - } - - switch (ctx->elf_hdr.e_ident[EI_DATA]) { - default: - fprintf(stderr, "ELF format error, wrong endianness info?\n"); - return -EINVAL; - case ELFDATA2LSB: - if (htons(1) == 1) { - fprintf(stderr, - "We are big endian, eBPF object is little endian!\n"); - return -EIO; - } - break; - case ELFDATA2MSB: - if (htons(1) != 1) { - fprintf(stderr, - "We are little endian, eBPF object is big endian!\n"); - return -EIO; - } - break; - } - - return 0; -} - -static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, - enum bpf_prog_type type, bool verbose) -{ - int ret = -EINVAL; - - if (elf_version(EV_CURRENT) == EV_NONE || - bpf_init_env(pathname)) - return ret; - - memset(ctx, 0, sizeof(*ctx)); - ctx->verbose = verbose; - ctx->type = type; - - ctx->obj_fd = open(pathname, O_RDONLY); - if (ctx->obj_fd < 0) - return ctx->obj_fd; - - ctx->elf_fd = elf_begin(ctx->obj_fd, ELF_C_READ, NULL); - if (!ctx->elf_fd) { - ret = -EINVAL; - goto out_fd; - } - - if (elf_kind(ctx->elf_fd) != ELF_K_ELF) { - ret = -EINVAL; - goto out_fd; - } - - if (gelf_getehdr(ctx->elf_fd, &ctx->elf_hdr) != - &ctx->elf_hdr) { - ret = -EIO; - goto out_elf; - } - - ret = bpf_elf_check_ehdr(ctx); - if (ret < 0) - goto out_elf; - - ctx->sec_done = calloc(ctx->elf_hdr.e_shnum, - sizeof(*(ctx->sec_done))); - if (!ctx->sec_done) { - ret = -ENOMEM; - goto out_elf; - } - - bpf_save_finfo(ctx); - bpf_hash_init(ctx, CONFDIR "/bpf_pinning"); - - return 0; -out_elf: - elf_end(ctx->elf_fd); -out_fd: - close(ctx->obj_fd); - return ret; -} - -static int bpf_maps_count(struct bpf_elf_ctx *ctx) -{ - int i, count = 0; - - for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++) { - if (!ctx->map_fds[i]) - break; - count++; - } - - return count; -} - -static void bpf_maps_teardown(struct bpf_elf_ctx *ctx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++) { - if (ctx->map_fds[i]) - close(ctx->map_fds[i]); - } -} - -static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure) -{ - if (failure) - bpf_maps_teardown(ctx); - - bpf_hash_destroy(ctx); - free(ctx->sec_done); - elf_end(ctx->elf_fd); - close(ctx->obj_fd); -} - -static struct bpf_elf_ctx __ctx; - -static int bpf_obj_open(const char *pathname, enum bpf_prog_type type, - const char *section, bool verbose) -{ - struct bpf_elf_ctx *ctx = &__ctx; - int fd = 0, ret; - - ret = bpf_elf_ctx_init(ctx, pathname, type, verbose); - if (ret < 0) { - fprintf(stderr, "Cannot initialize ELF context!\n"); - return ret; - } - - ret = bpf_fetch_ancillary(ctx); - if (ret < 0) { - fprintf(stderr, "Error fetching ELF ancillary data!\n"); - goto out; - } - - fd = bpf_fetch_prog_sec(ctx, section); - if (fd < 0) { - fprintf(stderr, "Error fetching program/map!\n"); - ret = fd; - goto out; - } - - ret = bpf_fill_prog_arrays(ctx); - if (ret < 0) - fprintf(stderr, "Error filling program arrays!\n"); -out: - bpf_elf_ctx_destroy(ctx, ret < 0); - if (ret < 0) { - if (fd) - close(fd); - return ret; - } - - return fd; -} - -static int -bpf_map_set_send(int fd, struct sockaddr_un *addr, unsigned int addr_len, - const struct bpf_map_data *aux, unsigned int entries) -{ - struct bpf_map_set_msg msg; - int *cmsg_buf, min_fd; - char *amsg_buf; - int i; - - memset(&msg, 0, sizeof(msg)); - - msg.aux.uds_ver = BPF_SCM_AUX_VER; - msg.aux.num_ent = entries; - - strncpy(msg.aux.obj_name, aux->obj, sizeof(msg.aux.obj_name)); - memcpy(&msg.aux.obj_st, aux->st, sizeof(msg.aux.obj_st)); - - cmsg_buf = bpf_map_set_init(&msg, addr, addr_len); - amsg_buf = (char *)msg.aux.ent; - - for (i = 0; i < entries; i += min_fd) { - int ret; - - min_fd = min(BPF_SCM_MAX_FDS * 1U, entries - i); - bpf_map_set_init_single(&msg, min_fd); - - memcpy(cmsg_buf, &aux->fds[i], sizeof(aux->fds[0]) * min_fd); - memcpy(amsg_buf, &aux->ent[i], sizeof(aux->ent[0]) * min_fd); - - ret = sendmsg(fd, &msg.hdr, 0); - if (ret <= 0) - return ret ? : -1; - } - - return 0; -} - -static int -bpf_map_set_recv(int fd, int *fds, struct bpf_map_aux *aux, - unsigned int entries) -{ - struct bpf_map_set_msg msg; - int *cmsg_buf, min_fd; - char *amsg_buf, *mmsg_buf; - unsigned int needed = 1; - int i; - - cmsg_buf = bpf_map_set_init(&msg, NULL, 0); - amsg_buf = (char *)msg.aux.ent; - mmsg_buf = (char *)&msg.aux; - - for (i = 0; i < min(entries, needed); i += min_fd) { - struct cmsghdr *cmsg; - int ret; - - min_fd = min(entries, entries - i); - bpf_map_set_init_single(&msg, min_fd); - - ret = recvmsg(fd, &msg.hdr, 0); - if (ret <= 0) - return ret ? : -1; - - cmsg = CMSG_FIRSTHDR(&msg.hdr); - if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS) - return -EINVAL; - if (msg.hdr.msg_flags & MSG_CTRUNC) - return -EIO; - if (msg.aux.uds_ver != BPF_SCM_AUX_VER) - return -ENOSYS; - - min_fd = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof(fd); - if (min_fd > entries || min_fd <= 0) - return -EINVAL; - - memcpy(&fds[i], cmsg_buf, sizeof(fds[0]) * min_fd); - memcpy(&aux->ent[i], amsg_buf, sizeof(aux->ent[0]) * min_fd); - memcpy(aux, mmsg_buf, offsetof(struct bpf_map_aux, ent)); - - needed = aux->num_ent; - } - - return 0; -} - -int bpf_send_map_fds(const char *path, const char *obj) -{ - struct bpf_elf_ctx *ctx = &__ctx; - struct sockaddr_un addr; - struct bpf_map_data bpf_aux; - int fd, ret; - - fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (fd < 0) { - fprintf(stderr, "Cannot open socket: %s\n", - strerror(errno)); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path)); - - ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret < 0) { - fprintf(stderr, "Cannot connect to %s: %s\n", - path, strerror(errno)); - return -1; - } - - memset(&bpf_aux, 0, sizeof(bpf_aux)); - - bpf_aux.fds = ctx->map_fds; - bpf_aux.ent = ctx->maps; - bpf_aux.st = &ctx->stat; - bpf_aux.obj = obj; - - ret = bpf_map_set_send(fd, &addr, sizeof(addr), &bpf_aux, - bpf_maps_count(ctx)); - if (ret < 0) - fprintf(stderr, "Cannot send fds to %s: %s\n", - path, strerror(errno)); - - bpf_maps_teardown(ctx); - close(fd); - return ret; -} - -int bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux, - unsigned int entries) -{ - struct sockaddr_un addr; - int fd, ret; - - fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (fd < 0) { - fprintf(stderr, "Cannot open socket: %s\n", - strerror(errno)); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path)); - - ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret < 0) { - fprintf(stderr, "Cannot bind to socket: %s\n", - strerror(errno)); - return -1; - } - - ret = bpf_map_set_recv(fd, fds, aux, entries); - if (ret < 0) - fprintf(stderr, "Cannot recv fds from %s: %s\n", - path, strerror(errno)); - - unlink(addr.sun_path); - close(fd); - return ret; -} -#endif /* HAVE_ELF */ diff --git a/tc/tc_bpf.h b/tc/tc_bpf.h deleted file mode 100644 index 526d0b12..00000000 --- a/tc/tc_bpf.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * tc_bpf.h BPF common code - * - * This program is free software; you can distribute 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: Daniel Borkmann <dborkman@redhat.com> - * Jiri Pirko <jiri@resnulli.us> - */ - -#ifndef _TC_BPF_H_ -#define _TC_BPF_H_ 1 - -#include <linux/netlink.h> -#include <linux/bpf.h> -#include <linux/magic.h> - -#include "utils.h" -#include "bpf_scm.h" - -enum { - BPF_NLA_OPS_LEN = 0, - BPF_NLA_OPS, - BPF_NLA_FD, - BPF_NLA_NAME, - __BPF_NLA_MAX, -}; - -#define BPF_NLA_MAX __BPF_NLA_MAX - -#define BPF_ENV_UDS "TC_BPF_UDS" -#define BPF_ENV_MNT "TC_BPF_MNT" -#define BPF_ENV_NOLOG "TC_BPF_NOLOG" - -#ifndef BPF_FS_MAGIC -# define BPF_FS_MAGIC 0xcafe4a11 -#endif - -#define BPF_DIR_MNT "/sys/fs/bpf" - -#define BPF_DIR_TC "tc" -#define BPF_DIR_GLOBALS "globals" - -#ifndef TRACEFS_MAGIC -# define TRACEFS_MAGIC 0x74726163 -#endif - -#define TRACE_DIR_MNT "/sys/kernel/tracing" - -int bpf_trace_pipe(void); -const char *bpf_default_section(const enum bpf_prog_type type); - -int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, - enum bpf_prog_type type, const char **ptr_object, - const char **ptr_uds_name, struct nlmsghdr *n); -int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv); - -void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len); - -#ifdef HAVE_ELF -int bpf_send_map_fds(const char *path, const char *obj); -int bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux, - unsigned int entries); -#else -static inline int bpf_send_map_fds(const char *path, const char *obj) -{ - return 0; -} - -static inline int bpf_recv_map_fds(const char *path, int *fds, - struct bpf_map_aux *aux, - unsigned int entries) -{ - return -1; -} -#endif /* HAVE_ELF */ -#endif /* _TC_BPF_H_ */ diff --git a/tc/tc_cbq.c b/tc/tc_cbq.c index 0bb262eb..5e50afa8 100644 --- a/tc/tc_cbq.c +++ b/tc/tc_cbq.c @@ -24,8 +24,8 @@ #include "tc_core.h" #include "tc_cbq.h" -unsigned tc_cbq_calc_maxidle(unsigned bndw, unsigned rate, unsigned avpkt, - int ewma_log, unsigned maxburst) +unsigned int tc_cbq_calc_maxidle(unsigned int bndw, unsigned int rate, unsigned int avpkt, + int ewma_log, unsigned int maxburst) { double maxidle; double g = 1.0 - 1.0/(1<<ewma_log); @@ -34,6 +34,7 @@ unsigned tc_cbq_calc_maxidle(unsigned bndw, unsigned rate, unsigned avpkt, maxidle = xmt*(1-g); if (bndw != rate && maxburst) { double vxmt = (double)avpkt/rate - xmt; + vxmt *= (pow(g, -(double)maxburst) - 1); if (vxmt > maxidle) maxidle = vxmt; @@ -41,8 +42,8 @@ unsigned tc_cbq_calc_maxidle(unsigned bndw, unsigned rate, unsigned avpkt, return tc_core_time2tick(maxidle*(1<<ewma_log)*TIME_UNITS_PER_SEC); } -unsigned tc_cbq_calc_offtime(unsigned bndw, unsigned rate, unsigned avpkt, - int ewma_log, unsigned minburst) +unsigned int tc_cbq_calc_offtime(unsigned int bndw, unsigned int rate, unsigned int avpkt, + int ewma_log, unsigned int minburst) { double g = 1.0 - 1.0/(1<<ewma_log); double offtime = (double)avpkt/rate - (double)avpkt/bndw; diff --git a/tc/tc_class.c b/tc/tc_class.c index 3acd030f..1a1f1fa2 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -24,7 +24,7 @@ #include "utils.h" #include "tc_util.h" #include "tc_common.h" -#include "hlist.h" +#include "list.h" struct graph_node { struct hlist_node hlist; @@ -52,30 +52,24 @@ static void usage(void) fprintf(stderr, "Where:\n"); fprintf(stderr, "QDISC_KIND := { prio | cbq | etc. }\n"); fprintf(stderr, "OPTIONS := ... try tc class add <desired QDISC_KIND> help\n"); - return; } -static int tc_class_modify(int cmd, unsigned flags, int argc, char **argv) +static int tc_class_modify(int cmd, unsigned int flags, int argc, char **argv) { struct { - struct nlmsghdr n; - struct tcmsg t; - char buf[4096]; - } req; + struct nlmsghdr n; + struct tcmsg t; + char buf[4096]; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .t.tcm_family = AF_UNSPEC, + }; struct qdisc_util *q = NULL; - struct tc_estimator est; - char d[16]; - char k[16]; - - memset(&req, 0, sizeof(req)); - memset(&est, 0, sizeof(est)); - memset(d, 0, sizeof(d)); - memset(k, 0, sizeof(k)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.t.tcm_family = AF_UNSPEC; + struct tc_estimator est = {}; + char d[16] = {}; + char k[16] = {}; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -85,6 +79,7 @@ static int tc_class_modify(int cmd, unsigned flags, int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "classid") == 0) { __u32 handle; + NEXT_ARG(); if (req.t.tcm_handle) duparg("classid", *argv); @@ -102,6 +97,7 @@ static int tc_class_modify(int cmd, unsigned flags, int argc, char **argv) req.t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + NEXT_ARG(); if (req.t.tcm_parent) duparg("parent", *argv); @@ -166,9 +162,8 @@ __u32 filter_classid; static void graph_node_add(__u32 parent_id, __u32 id, void *data, int len) { - struct graph_node *node = malloc(sizeof(struct graph_node)); + struct graph_node *node = calloc(1, sizeof(struct graph_node)); - memset(node, 0, sizeof(*node)); node->id = id; node->parent_id = parent_id; @@ -223,7 +218,7 @@ static void graph_cls_show(FILE *fp, char *buf, struct hlist_head *root_list, { struct hlist_node *n, *tmp_cls; char cls_id_str[256] = {}; - struct rtattr *tb[TCA_MAX + 1] = {}; + struct rtattr *tb[TCA_MAX + 1]; struct qdisc_util *q; char str[100] = {}; @@ -305,10 +300,10 @@ static void graph_cls_show(FILE *fp, char *buf, struct hlist_head *root_list, int print_class(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr *tb[TCA_MAX + 1] = {}; + struct rtattr *tb[TCA_MAX + 1]; struct qdisc_util *q; char abuf[256]; @@ -393,14 +388,10 @@ int print_class(const struct sockaddr_nl *who, static int tc_class_list(int argc, char **argv) { - struct tcmsg t; - char d[16]; + struct tcmsg t = { .tcm_family = AF_UNSPEC }; + char d[16] = {}; char buf[1024] = {0}; - memset(&t, 0, sizeof(t)); - t.tcm_family = AF_UNSPEC; - memset(d, 0, sizeof(d)); - filter_qdisc = 0; filter_classid = 0; @@ -430,6 +421,7 @@ static int tc_class_list(int argc, char **argv) t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + if (t.tcm_parent) duparg("parent", *argv); NEXT_ARG(); diff --git a/tc/tc_core.c b/tc/tc_core.c index 46eaefb5..821b741b 100644 --- a/tc/tc_core.c +++ b/tc/tc_core.c @@ -12,6 +12,7 @@ #include <stdio.h> #include <stdlib.h> +#include <stdint.h> #include <unistd.h> #include <syslog.h> #include <fcntl.h> @@ -27,7 +28,7 @@ static double tick_in_usec = 1; static double clock_factor = 1; -int tc_core_time2big(unsigned time) +int tc_core_time2big(unsigned int time) { __u64 t = time; @@ -36,32 +37,32 @@ int tc_core_time2big(unsigned time) } -unsigned tc_core_time2tick(unsigned time) +unsigned int tc_core_time2tick(unsigned int time) { return time*tick_in_usec; } -unsigned tc_core_tick2time(unsigned tick) +unsigned int tc_core_tick2time(unsigned int tick) { return tick/tick_in_usec; } -unsigned tc_core_time2ktime(unsigned time) +unsigned int tc_core_time2ktime(unsigned int time) { return time * clock_factor; } -unsigned tc_core_ktime2time(unsigned ktime) +unsigned int tc_core_ktime2time(unsigned int ktime) { return ktime / clock_factor; } -unsigned tc_calc_xmittime(__u64 rate, unsigned size) +unsigned int tc_calc_xmittime(__u64 rate, unsigned int size) { return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/(double)rate)); } -unsigned tc_calc_xmitsize(__u64 rate, unsigned ticks) +unsigned int tc_calc_xmitsize(__u64 rate, unsigned int ticks) { return ((double)rate*tc_core_tick2time(ticks))/TIME_UNITS_PER_SEC; } @@ -76,9 +77,10 @@ unsigned tc_calc_xmitsize(__u64 rate, unsigned ticks) * (as the table will always be aligned for 48 bytes). * --Hawk, d.7/11-2004. <hawk@diku.dk> */ -static unsigned tc_align_to_atm(unsigned size) +static unsigned int tc_align_to_atm(unsigned int size) { int linksize, cells; + cells = size / ATM_CELL_PAYLOAD; if ((size % ATM_CELL_PAYLOAD) > 0) cells++; @@ -87,7 +89,7 @@ static unsigned tc_align_to_atm(unsigned size) return linksize; } -static unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linklayer) +static unsigned int tc_adjust_size(unsigned int sz, unsigned int mpu, enum link_layer linklayer) { if (sz < mpu) sz = mpu; @@ -97,7 +99,7 @@ static unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linkla return tc_align_to_atm(sz); case LINKLAYER_ETHERNET: default: - // No size adjustments on Ethernet + /* No size adjustments on Ethernet */ return sz; } } @@ -122,13 +124,13 @@ static unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linkla */ int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab, - int cell_log, unsigned mtu, + int cell_log, unsigned int mtu, enum link_layer linklayer) { int i; - unsigned sz; - unsigned bps = r->rate; - unsigned mpu = r->mpu; + unsigned int sz; + unsigned int bps = r->rate; + unsigned int mpu = r->mpu; if (mtu == 0) mtu = 2047; @@ -139,13 +141,13 @@ int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab, cell_log++; } - for (i=0; i<256; i++) { + for (i = 0; i < 256; i++) { sz = tc_adjust_size((i + 1) << cell_log, mpu, linklayer); rtab[i] = tc_calc_xmittime(bps, sz); } - r->cell_align=-1; // Due to the sz calc - r->cell_log=cell_log; + r->cell_align = -1; + r->cell_log = cell_log; r->linklayer = (linklayer & TC_LINKLAYER_MASK); return cell_log; } @@ -193,7 +195,7 @@ again: (*stab)[i] = sz >> s->size_log; } - s->cell_align = -1; // Due to the sz calc + s->cell_align = -1; /* Due to the sz calc */ return 0; } diff --git a/tc/tc_estimator.c b/tc/tc_estimator.c index e559add1..c40eea96 100644 --- a/tc/tc_estimator.c +++ b/tc/tc_estimator.c @@ -23,22 +23,23 @@ #include "tc_core.h" -int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est) +int tc_setup_estimator(unsigned int A, unsigned int time_const, struct tc_estimator *est) { - for (est->interval=0; est->interval<=5; est->interval++) { + for (est->interval = 0; est->interval <= 5; est->interval++) { if (A <= (1<<est->interval)*(TIME_UNITS_PER_SEC/4)) break; } if (est->interval > 5) return -1; est->interval -= 2; - for (est->ewma_log=1; est->ewma_log<32; est->ewma_log++) { + for (est->ewma_log = 1; est->ewma_log < 32; est->ewma_log++) { double w = 1.0 - 1.0/(1<<est->ewma_log); + if (A/(-log(w)) > time_const) break; } est->ewma_log--; - if (est->ewma_log==0 || est->ewma_log >= 31) + if (est->ewma_log == 0 || est->ewma_log >= 31) return -1; return 0; } diff --git a/tc/tc_exec.c b/tc/tc_exec.c index 61be6721..d23a825d 100644 --- a/tc/tc_exec.c +++ b/tc/tc_exec.c @@ -19,7 +19,7 @@ #include "tc_common.h" static struct exec_util *exec_list; -static void *BODY = NULL; +static void *BODY; static void usage(void) { @@ -32,8 +32,8 @@ static void usage(void) static int parse_noeopt(struct exec_util *eu, int argc, char **argv) { if (argc) { - fprintf(stderr, "Unknown exec \"%s\", hence option \"%s\" " - "is unparsable\n", eu->id, *argv); + fprintf(stderr, "Unknown exec \"%s\", hence option \"%s\" is unparsable\n", + eu->id, *argv); return -1; } @@ -71,9 +71,8 @@ reg: return eu; noexist: - eu = malloc(sizeof(*eu)); + eu = calloc(1, sizeof(*eu)); if (eu) { - memset(eu, 0, sizeof(*eu)); strncpy(eu->id, name, sizeof(eu->id) - 1); eu->parse_eopt = parse_noeopt; goto reg; @@ -85,7 +84,7 @@ noexist: int do_exec(int argc, char **argv) { struct exec_util *eu; - char kind[16]; + char kind[16] = {}; if (argc < 1) { fprintf(stderr, "No command given, try \"tc exec help\".\n"); @@ -97,7 +96,6 @@ int do_exec(int argc, char **argv) return 0; } - memset(kind, 0, sizeof(kind)); strncpy(kind, *argv, sizeof(kind) - 1); eu = get_exec_kind(kind); diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 1a1082b4..cf290ae8 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -28,45 +28,43 @@ static void usage(void) { - fprintf(stderr, "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n"); - fprintf(stderr, " [ pref PRIO ] protocol PROTO\n"); - fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n"); - fprintf(stderr, " [ root | ingress | egress | parent CLASSID ]\n"); - fprintf(stderr, " [ handle FILTERID ] [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " tc filter show [ dev STRING ] [ root | ingress | egress | parent CLASSID ]\n"); - fprintf(stderr, "Where:\n"); - fprintf(stderr, "FILTER_TYPE := { rsvp | u32 | bpf | fw | route | etc. }\n"); - fprintf(stderr, "FILTERID := ... format depends on classifier, see there\n"); - fprintf(stderr, "OPTIONS := ... try tc filter add <desired FILTER_KIND> help\n"); + fprintf(stderr, + "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n" + "Usage: tc filter get dev STRING parent CLASSID protocol PROTO handle FILTERID pref PRIO FILTER_TYPE\n" + " [ pref PRIO ] protocol PROTO [ chain CHAIN_INDEX ]\n" + " [ estimator INTERVAL TIME_CONSTANT ]\n" + " [ root | ingress | egress | parent CLASSID ]\n" + " [ handle FILTERID ] [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n" + "\n" + " tc filter show [ dev STRING ] [ root | ingress | egress | parent CLASSID ]\n" + "Where:\n" + "FILTER_TYPE := { rsvp | u32 | bpf | fw | route | etc. }\n" + "FILTERID := ... format depends on classifier, see there\n" + "OPTIONS := ... try tc filter add <desired FILTER_KIND> help\n"); } -static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) +static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) { struct { - struct nlmsghdr n; - struct tcmsg t; - char buf[MAX_MSG]; - } req; + struct nlmsghdr n; + struct tcmsg t; + char buf[MAX_MSG]; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .t.tcm_family = AF_UNSPEC, + }; struct filter_util *q = NULL; __u32 prio = 0; __u32 protocol = 0; int protocol_set = 0; + __u32 chain_index; + int chain_index_set = 0; char *fhandle = NULL; - char d[16]; - char k[16]; - struct tc_estimator est; - - memset(&req, 0, sizeof(req)); - memset(&est, 0, sizeof(est)); - memset(d, 0, sizeof(d)); - memset(k, 0, sizeof(k)); - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.t.tcm_family = AF_UNSPEC; + char d[16] = {}; + char k[16] = {}; + struct tc_estimator est = {}; if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE) protocol = htons(ETH_P_ALL); @@ -79,26 +77,30 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "root") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"root\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "ingress") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"ingress\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"ingress\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); } else if (strcmp(*argv, "egress") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"egress\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"egress\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS); } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + NEXT_ARG(); if (req.t.tcm_parent) duparg("parent", *argv); @@ -119,6 +121,7 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) invarg("invalid priority value", *argv); } else if (matches(*argv, "protocol") == 0) { __u16 id; + NEXT_ARG(); if (protocol_set) duparg("protocol", *argv); @@ -126,6 +129,13 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) invarg("invalid protocol", *argv); protocol = id; protocol_set = 1; + } else if (matches(*argv, "chain") == 0) { + NEXT_ARG(); + if (chain_index_set) + duparg("chain", *argv); + if (get_u32(&chain_index, *argv, 0)) + invarg("invalid chain index value", *argv); + chain_index_set = 1; } else if (matches(*argv, "estimator") == 0) { if (parse_estimator(&argc, &argv, &est) < 0) return -1; @@ -145,6 +155,9 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) req.t.tcm_info = TC_H_MAKE(prio<<16, protocol); + if (chain_index_set) + addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index); + if (k[0]) addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); @@ -153,17 +166,20 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) return 1; } else { if (fhandle) { - fprintf(stderr, "Must specify filter type when using " - "\"handle\"\n"); + fprintf(stderr, + "Must specify filter type when using \"handle\"\n"); return -1; } if (argc) { if (matches(*argv, "help") == 0) usage(); - fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", *argv); + fprintf(stderr, + "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", + *argv); return -1; } } + if (est.ewma_log) addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est)); @@ -171,7 +187,8 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) if (d[0]) { ll_init_map(&rth); - if ((req.t.tcm_ifindex = ll_name_to_index(d)) == 0) { + req.t.tcm_ifindex = ll_name_to_index(d); + if (req.t.tcm_ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } @@ -189,21 +206,23 @@ static __u32 filter_parent; static int filter_ifindex; static __u32 filter_prio; static __u32 filter_protocol; -__u16 f_proto = 0; +static __u32 filter_chain_index; +static int filter_chain_index_set; +__u16 f_proto; -int print_filter(const struct sockaddr_nl *who, - struct nlmsghdr *n, - void *arg) +int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[TCA_MAX+1]; + struct rtattr *tb[TCA_MAX+1]; struct filter_util *q; char abuf[256]; - if (n->nlmsg_type != RTM_NEWTFILTER && n->nlmsg_type != RTM_DELTFILTER) { - fprintf(stderr, "Not a filter\n"); + if (n->nlmsg_type != RTM_NEWTFILTER && + n->nlmsg_type != RTM_GETTFILTER && + n->nlmsg_type != RTM_DELTFILTER) { + fprintf(stderr, "Not a filter(cmd %d)\n", n->nlmsg_type); return 0; } len -= NLMSG_LENGTH(sizeof(*t)); @@ -212,7 +231,6 @@ int print_filter(const struct sockaddr_nl *who, return -1; } - memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { @@ -223,6 +241,16 @@ int print_filter(const struct sockaddr_nl *who, if (n->nlmsg_type == RTM_DELTFILTER) fprintf(fp, "deleted "); + if (n->nlmsg_type == RTM_NEWTFILTER && + (n->nlmsg_flags & NLM_F_CREATE) && + !(n->nlmsg_flags & NLM_F_EXCL)) + fprintf(fp, "replaced "); + + if (n->nlmsg_type == RTM_NEWTFILTER && + (n->nlmsg_flags & NLM_F_CREATE) && + (n->nlmsg_flags & NLM_F_EXCL)) + fprintf(fp, "added "); + fprintf(fp, "filter "); if (!filter_ifindex || filter_ifindex != t->tcm_ifindex) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); @@ -243,6 +271,7 @@ int print_filter(const struct sockaddr_nl *who, if (t->tcm_info) { f_proto = TC_H_MIN(t->tcm_info); __u32 prio = TC_H_MAJ(t->tcm_info)>>16; + if (!filter_protocol || filter_protocol != f_proto) { if (f_proto) { SPRINT_BUF(b1); @@ -256,6 +285,15 @@ int print_filter(const struct sockaddr_nl *who, } } fprintf(fp, "%s ", rta_getattr_str(tb[TCA_KIND])); + + if (tb[TCA_CHAIN]) { + __u32 chain_index = rta_getattr_u32(tb[TCA_CHAIN]); + + if (!filter_chain_index_set || + filter_chain_index != chain_index) + fprintf(fp, "chain %u ", chain_index); + } + q = get_filter_kind(RTA_DATA(tb[TCA_KIND])); if (tb[TCA_OPTIONS]) { if (q) @@ -274,17 +312,205 @@ int print_filter(const struct sockaddr_nl *who, return 0; } -static int tc_filter_list(int argc, char **argv) +static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) { - struct tcmsg t; - char d[16]; + struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[MAX_MSG]; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + /* NLM_F_ECHO is for backward compatibility. old kernels never + * respond without it and newer kernels will ignore it. + * In old kernels there is a side effect: + * In addition to a response to the GET you will receive an + * event (if you do tc mon). + */ + .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ECHO | flags, + .n.nlmsg_type = cmd, + .t.tcm_parent = TC_H_UNSPEC, + .t.tcm_family = AF_UNSPEC, + }; + struct filter_util *q = NULL; __u32 prio = 0; __u32 protocol = 0; + int protocol_set = 0; + __u32 chain_index; + int chain_index_set = 0; + __u32 parent_handle = 0; char *fhandle = NULL; + char d[16] = {}; + char k[16] = {}; + + while (argc > 0) { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + if (d[0]) + duparg("dev", *argv); + strncpy(d, *argv, sizeof(d)-1); + } else if (strcmp(*argv, "root") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, + "Error: \"root\" is duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_ROOT; + } else if (strcmp(*argv, "ingress") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, + "Error: \"ingress\" is duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, + TC_H_MIN_INGRESS); + } else if (strcmp(*argv, "egress") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, + "Error: \"egress\" is duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, + TC_H_MIN_EGRESS); + } else if (strcmp(*argv, "parent") == 0) { + + NEXT_ARG(); + if (req.t.tcm_parent) + duparg("parent", *argv); + if (get_tc_classid(&parent_handle, *argv)) + invarg("Invalid parent ID", *argv); + req.t.tcm_parent = parent_handle; + } else if (strcmp(*argv, "handle") == 0) { + NEXT_ARG(); + if (fhandle) + duparg("handle", *argv); + fhandle = *argv; + } else if (matches(*argv, "preference") == 0 || + matches(*argv, "priority") == 0) { + NEXT_ARG(); + if (prio) + duparg("priority", *argv); + if (get_u32(&prio, *argv, 0) || prio > 0xFFFF) + invarg("invalid priority value", *argv); + } else if (matches(*argv, "protocol") == 0) { + __u16 id; + + NEXT_ARG(); + if (protocol_set) + duparg("protocol", *argv); + if (ll_proto_a2n(&id, *argv)) + invarg("invalid protocol", *argv); + protocol = id; + protocol_set = 1; + } else if (matches(*argv, "chain") == 0) { + NEXT_ARG(); + if (chain_index_set) + duparg("chain", *argv); + if (get_u32(&chain_index, *argv, 0)) + invarg("invalid chain index value", *argv); + chain_index_set = 1; + } else if (matches(*argv, "help") == 0) { + usage(); + return 0; + } else { + if (!**argv) + invarg("invalid filter name", *argv); + + strncpy(k, *argv, sizeof(k)-1); + + q = get_filter_kind(k); + argc--; argv++; + break; + } - memset(&t, 0, sizeof(t)); - t.tcm_family = AF_UNSPEC; - memset(d, 0, sizeof(d)); + argc--; argv++; + } + + if (!protocol_set) { + fprintf(stderr, "Must specify filter protocol\n"); + return -1; + } + + if (!prio) { + fprintf(stderr, "Must specify filter priority\n"); + return -1; + } + + req.t.tcm_info = TC_H_MAKE(prio<<16, protocol); + + if (chain_index_set) + addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index); + + if (req.t.tcm_parent == TC_H_UNSPEC) { + fprintf(stderr, "Must specify filter parent\n"); + return -1; + } + + if (k[0]) + addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); + else { + fprintf(stderr, "Must specify filter type\n"); + return -1; + } + + if (q->parse_fopt(q, fhandle, argc, argv, &req.n)) + return 1; + + + if (!fhandle) { + fprintf(stderr, "Must specify filter \"handle\"\n"); + return -1; + } + + if (argc) { + if (matches(*argv, "help") == 0) + usage(); + fprintf(stderr, + "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", + *argv); + return -1; + } + + if (d[0]) { + ll_init_map(&rth); + + req.t.tcm_ifindex = ll_name_to_index(d); + if (req.t.tcm_ifindex == 0) { + fprintf(stderr, "Cannot find device \"%s\"\n", d); + return 1; + } + filter_ifindex = req.t.tcm_ifindex; + } else { + fprintf(stderr, "Must specify netdevice \"dev\"\n"); + return -1; + } + + if (rtnl_talk(&rth, &req.n, &req.n, MAX_MSG) < 0) { + fprintf(stderr, "We have an error talking to the kernel\n"); + return 2; + } + + print_filter(NULL, &req.n, (void *)stdout); + + return 0; +} + +static int tc_filter_list(int argc, char **argv) +{ + struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[MAX_MSG]; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .n.nlmsg_type = RTM_GETTFILTER, + .t.tcm_parent = TC_H_UNSPEC, + .t.tcm_family = AF_UNSPEC, + }; + char d[16] = {}; + __u32 prio = 0; + __u32 protocol = 0; + __u32 chain_index; + char *fhandle = NULL; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -293,35 +519,39 @@ static int tc_filter_list(int argc, char **argv) duparg("dev", *argv); strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "root") == 0) { - if (t.tcm_parent) { - fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); + if (req.t.tcm_parent) { + fprintf(stderr, + "Error: \"root\" is duplicate parent ID\n"); return -1; } - filter_parent = t.tcm_parent = TC_H_ROOT; + filter_parent = req.t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "ingress") == 0) { - if (t.tcm_parent) { - fprintf(stderr, "Error: \"ingress\" is duplicate parent ID\n"); + if (req.t.tcm_parent) { + fprintf(stderr, + "Error: \"ingress\" is duplicate parent ID\n"); return -1; } filter_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); - t.tcm_parent = filter_parent; + req.t.tcm_parent = filter_parent; } else if (strcmp(*argv, "egress") == 0) { - if (t.tcm_parent) { - fprintf(stderr, "Error: \"egress\" is duplicate parent ID\n"); + if (req.t.tcm_parent) { + fprintf(stderr, + "Error: \"egress\" is duplicate parent ID\n"); return -1; } filter_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS); - t.tcm_parent = filter_parent; + req.t.tcm_parent = filter_parent; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + NEXT_ARG(); - if (t.tcm_parent) + if (req.t.tcm_parent) duparg("parent", *argv); if (get_tc_classid(&handle, *argv)) invarg("invalid parent ID", *argv); - filter_parent = t.tcm_parent = handle; + filter_parent = req.t.tcm_parent = handle; } else if (strcmp(*argv, "handle") == 0) { NEXT_ARG(); if (fhandle) @@ -337,6 +567,7 @@ static int tc_filter_list(int argc, char **argv) filter_prio = prio; } else if (matches(*argv, "protocol") == 0) { __u16 res; + NEXT_ARG(); if (protocol) duparg("protocol", *argv); @@ -344,29 +575,43 @@ static int tc_filter_list(int argc, char **argv) invarg("invalid protocol", *argv); protocol = res; filter_protocol = protocol; + } else if (matches(*argv, "chain") == 0) { + NEXT_ARG(); + if (filter_chain_index_set) + duparg("chain", *argv); + if (get_u32(&chain_index, *argv, 0)) + invarg("invalid chain index value", *argv); + filter_chain_index_set = 1; + filter_chain_index = chain_index; } else if (matches(*argv, "help") == 0) { usage(); } else { - fprintf(stderr, " What is \"%s\"? Try \"tc filter help\"\n", *argv); + fprintf(stderr, + " What is \"%s\"? Try \"tc filter help\"\n", + *argv); return -1; } argc--; argv++; } - t.tcm_info = TC_H_MAKE(prio<<16, protocol); + req.t.tcm_info = TC_H_MAKE(prio<<16, protocol); ll_init_map(&rth); if (d[0]) { - if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) { + req.t.tcm_ifindex = ll_name_to_index(d); + if (req.t.tcm_ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } - filter_ifindex = t.tcm_ifindex; + filter_ifindex = req.t.tcm_ifindex; } - if (rtnl_dump_request(&rth, RTM_GETTFILTER, &t, sizeof(t)) < 0) { + if (filter_chain_index_set) + addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index); + + if (rtnl_dump_request_n(&rth, &req.n) < 0) { perror("Cannot send dump request"); return 1; } @@ -384,24 +629,25 @@ int do_filter(int argc, char **argv) if (argc < 1) return tc_filter_list(0, NULL); if (matches(*argv, "add") == 0) - return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE, argc-1, argv+1); + return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE, + argc-1, argv+1); if (matches(*argv, "change") == 0) return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1); if (matches(*argv, "replace") == 0) - return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1, argv+1); + return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1, + argv+1); if (matches(*argv, "delete") == 0) return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1); -#if 0 if (matches(*argv, "get") == 0) return tc_filter_get(RTM_GETTFILTER, 0, argc-1, argv+1); -#endif if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 || matches(*argv, "lst") == 0) return tc_filter_list(argc-1, argv+1); if (matches(*argv, "help") == 0) { usage(); return 0; - } - fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n", *argv); + } + fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n", + *argv); return -1; } diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c index ebb94320..83142cb2 100644 --- a/tc/tc_monitor.c +++ b/tc/tc_monitor.c @@ -39,7 +39,7 @@ static int accept_tcmsg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; if (timestamp) print_timestamp(fp); @@ -73,7 +73,7 @@ int do_tcmonitor(int argc, char **argv) { struct rtnl_handle rth; char *file = NULL; - unsigned groups = nl_mgrp(RTNLGRP_TC); + unsigned int groups = nl_mgrp(RTNLGRP_TC); while (argc > 0) { if (matches(*argv, "file") == 0) { @@ -109,7 +109,7 @@ int do_tcmonitor(int argc, char **argv) ll_init_map(&rth); - if (rtnl_listen(&rth, accept_tcmsg, (void*)stdout) < 0) { + if (rtnl_listen(&rth, accept_tcmsg, (void *)stdout) < 0) { rtnl_close(&rth); exit(2); } diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index cb861e08..493538c2 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -34,7 +34,7 @@ static int usage(void) fprintf(stderr, " [ stab [ help | STAB_OPTIONS] ]\n"); fprintf(stderr, " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n"); fprintf(stderr, "\n"); - fprintf(stderr, " tc qdisc show [ dev STRING ] [ ingress | clsact ]\n"); + fprintf(stderr, " tc qdisc show [ dev STRING ] [ ingress | clsact ] [ invisible ]\n"); fprintf(stderr, "Where:\n"); fprintf(stderr, "QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n"); fprintf(stderr, "OPTIONS := ... try tc qdisc add <desired QDISC_KIND> help\n"); @@ -42,32 +42,26 @@ static int usage(void) return -1; } -static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) +static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) { struct qdisc_util *q = NULL; - struct tc_estimator est; + struct tc_estimator est = {}; struct { struct tc_sizespec szopts; __u16 *data; - } stab; - char d[16]; - char k[16]; + } stab = {}; + char d[16] = {}; + char k[16] = {}; struct { - struct nlmsghdr n; - struct tcmsg t; - char buf[TCA_BUF_MAX]; - } req; - - memset(&req, 0, sizeof(req)); - memset(&stab, 0, sizeof(stab)); - memset(&est, 0, sizeof(est)); - memset(&d, 0, sizeof(d)); - memset(&k, 0, sizeof(k)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.t.tcm_family = AF_UNSPEC; + struct nlmsghdr n; + struct tcmsg t; + char buf[TCA_BUF_MAX]; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .t.tcm_family = AF_UNSPEC, + }; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -77,6 +71,7 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "handle") == 0) { __u32 handle; + if (req.t.tcm_handle) duparg("handle", *argv); NEXT_ARG(); @@ -113,6 +108,7 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) break; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + NEXT_ARG(); if (req.t.tcm_parent) duparg("parent", *argv); @@ -186,7 +182,8 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) ll_init_map(&rth); - if ((idx = ll_name_to_index(d)) == 0) { + idx = ll_name_to_index(d); + if (idx == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } @@ -202,13 +199,12 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) static int filter_ifindex; int print_qdisc(const struct sockaddr_nl *who, - struct nlmsghdr *n, - void *arg) + struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[TCA_MAX+1]; + struct rtattr *tb[TCA_MAX+1]; struct qdisc_util *q; char abuf[256]; @@ -225,7 +221,6 @@ int print_qdisc(const struct sockaddr_nl *who, if (filter_ifindex && filter_ifindex != t->tcm_ifindex) return 0; - memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { @@ -236,21 +231,39 @@ int print_qdisc(const struct sockaddr_nl *who, if (n->nlmsg_type == RTM_DELQDISC) fprintf(fp, "deleted "); - fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), t->tcm_handle>>16); + if (n->nlmsg_type == RTM_NEWQDISC && + (n->nlmsg_flags & NLM_F_CREATE) && + (n->nlmsg_flags & NLM_F_REPLACE)) + fprintf(fp, "replaced "); + + if (n->nlmsg_type == RTM_NEWQDISC && + (n->nlmsg_flags & NLM_F_CREATE) && + (n->nlmsg_flags & NLM_F_EXCL)) + fprintf(fp, "added "); + + if (show_raw) + fprintf(fp, "qdisc %s %x:[%08x] ", + rta_getattr_str(tb[TCA_KIND]), + t->tcm_handle >> 16, t->tcm_handle); + else + fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), + t->tcm_handle >> 16); + if (filter_ifindex == 0) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); + if (t->tcm_parent == TC_H_ROOT) fprintf(fp, "root "); else if (t->tcm_parent) { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); fprintf(fp, "parent %s ", abuf); } - if (t->tcm_info != 1) { + + if (t->tcm_info != 1) fprintf(fp, "refcnt %d ", t->tcm_info); - } - /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ - if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND]))) + /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ + if (strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])) == 0) q = get_qdisc_kind("prio"); else q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND])); @@ -262,10 +275,12 @@ int print_qdisc(const struct sockaddr_nl *who, fprintf(fp, "[cannot parse qdisc parameters]"); } fprintf(fp, "\n"); + if (show_details && tb[TCA_STAB]) { print_size_table(fp, " ", tb[TCA_STAB]); fprintf(fp, "\n"); } + if (show_stats) { struct rtattr *xstats = NULL; @@ -285,26 +300,25 @@ int print_qdisc(const struct sockaddr_nl *who, static int tc_qdisc_list(int argc, char **argv) { - struct tcmsg t; - char d[16]; - - memset(&t, 0, sizeof(t)); - t.tcm_family = AF_UNSPEC; - memset(&d, 0, sizeof(d)); + struct tcmsg t = { .tcm_family = AF_UNSPEC }; + char d[16] = {}; + bool dump_invisible = false; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); strncpy(d, *argv, sizeof(d)-1); - } else if (strcmp(*argv, "ingress") == 0 || + } else if (strcmp(*argv, "ingress") == 0 || strcmp(*argv, "clsact") == 0) { - if (t.tcm_parent) { - fprintf(stderr, "Duplicate parent ID\n"); - usage(); - } - t.tcm_parent = TC_H_INGRESS; + if (t.tcm_parent) { + fprintf(stderr, "Duplicate parent ID\n"); + usage(); + } + t.tcm_parent = TC_H_INGRESS; } else if (matches(*argv, "help") == 0) { usage(); + } else if (strcmp(*argv, "invisible") == 0) { + dump_invisible = true; } else { fprintf(stderr, "What is \"%s\"? Try \"tc qdisc help\".\n", *argv); return -1; @@ -316,14 +330,33 @@ static int tc_qdisc_list(int argc, char **argv) ll_init_map(&rth); if (d[0]) { - if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) { + t.tcm_ifindex = ll_name_to_index(d); + if (t.tcm_ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } filter_ifindex = t.tcm_ifindex; } - if (rtnl_dump_request(&rth, RTM_GETQDISC, &t, sizeof(t)) < 0) { + if (dump_invisible) { + struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[256]; + } req = { + .n.nlmsg_type = RTM_GETQDISC, + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + }; + + req.t.tcm_family = AF_UNSPEC; + + addattr(&req.n, 256, TCA_DUMP_INVISIBLE); + if (rtnl_dump_request_n(&rth, &req.n) < 0) { + perror("Cannot send dump request"); + return 1; + } + + } else if (rtnl_dump_request(&rth, RTM_GETQDISC, &t, sizeof(t)) < 0) { perror("Cannot send dump request"); return 1; } @@ -360,7 +393,7 @@ int do_qdisc(int argc, char **argv) if (matches(*argv, "help") == 0) { usage(); return 0; - } + } fprintf(stderr, "Command \"%s\" is unknown, try \"tc qdisc help\".\n", *argv); return -1; } diff --git a/tc/tc_red.c b/tc/tc_red.c index 81a83bd2..e9b2f0ee 100644 --- a/tc/tc_red.c +++ b/tc/tc_red.c @@ -27,7 +27,7 @@ /* Plog = log(prob/(qmax - qmin)) */ -int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob) +int tc_red_eval_P(unsigned int qmin, unsigned int qmax, double prob) { int i = qmax - qmin; @@ -36,12 +36,12 @@ int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob) prob /= i; - for (i=0; i<32; i++) { + for (i = 0; i < 32; i++) { if (prob > 1.0) break; prob *= 2; } - if (i>=32) + if (i >= 32) return -1; return i; } @@ -50,18 +50,18 @@ int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob) burst + 1 - qmin/avpkt < (1-(1-W)^burst)/W */ -int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt) +int tc_red_eval_ewma(unsigned int qmin, unsigned int burst, unsigned int avpkt) { int wlog = 1; double W = 0.5; double a = (double)burst + 1 - (double)qmin/avpkt; if (a < 1.0) { - fprintf(stderr, "tc_red_eval_ewma() burst %u is too small ?" - " Try burst %u\n", burst, 1 + qmin/avpkt); + fprintf(stderr, "tc_red_eval_ewma() burst %u is too small ? Try burst %u\n", + burst, 1 + qmin/avpkt); return -1; } - for (wlog=1; wlog<32; wlog++, W /= 2) { + for (wlog = 1; wlog < 32; wlog++, W /= 2) { if (a <= (1 - pow(1-W, burst))/W) return wlog; } @@ -72,7 +72,7 @@ int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt) Stab[t>>Scell_log] = -log(1-W) * t/xmit_time */ -int tc_red_eval_idle_damping(int Wlog, unsigned avpkt, unsigned bps, __u8 *sbuf) +int tc_red_eval_idle_damping(int Wlog, unsigned int avpkt, unsigned int bps, __u8 *sbuf) { double xmit_time = tc_calc_xmittime(bps, avpkt); double lW = -log(1.0 - 1.0/(1<<Wlog))/xmit_time; @@ -80,7 +80,7 @@ int tc_red_eval_idle_damping(int Wlog, unsigned avpkt, unsigned bps, __u8 *sbuf) int clog; int i; - for (clog=0; clog<32; clog++) { + for (clog = 0; clog < 32; clog++) { if (maxtime/(1<<clog) < 512) break; } @@ -88,7 +88,7 @@ int tc_red_eval_idle_damping(int Wlog, unsigned avpkt, unsigned bps, __u8 *sbuf) return -1; sbuf[0] = 0; - for (i=1; i<255; i++) { + for (i = 1; i < 255; i++) { sbuf[i] = (i<<clog)*lW; if (sbuf[i] > 31) sbuf[i] = 31; diff --git a/tc/tc_stab.c b/tc/tc_stab.c index aba8ae87..1a0a3e3f 100644 --- a/tc/tc_stab.c +++ b/tc/tc_stab.c @@ -31,7 +31,7 @@ static void stab_help(void) { fprintf(stderr, - "Usage: ... stab [ mtu BYTES ] [ tsize SLOTS ] [ mpu BYTES ] \n" + "Usage: ... stab [ mtu BYTES ] [ tsize SLOTS ] [ mpu BYTES ]\n" " [ overhead BYTES ] [ linklayer TYPE ] ...\n" " mtu : max packet size we create rate map for {2047}\n" " tsize : how many slots should size table have {512}\n" @@ -40,7 +40,6 @@ static void stab_help(void) " linklayer : adapting to a linklayer e.g. atm\n" "Example: ... stab overhead 20 linklayer atm\n"); - return; } int check_size_table_opts(struct tc_sizespec *s) @@ -53,9 +52,7 @@ int parse_size_table(int *argcp, char ***argvp, struct tc_sizespec *sp) { char **argv = *argvp; int argc = *argcp; - struct tc_sizespec s; - - memset(&s, 0, sizeof(s)); + struct tc_sizespec s = {}; NEXT_ARG(); if (matches(*argv, "help") == 0) { @@ -110,12 +107,14 @@ int parse_size_table(int *argcp, char ***argvp, struct tc_sizespec *sp) void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta) { struct rtattr *tb[TCA_STAB_MAX + 1]; + SPRINT_BUF(b1); parse_rtattr_nested(tb, TCA_STAB_MAX, rta); if (tb[TCA_STAB_BASE]) { struct tc_sizespec s = {0}; + memcpy(&s, RTA_DATA(tb[TCA_STAB_BASE]), MIN(RTA_PAYLOAD(tb[TCA_STAB_BASE]), sizeof(s))); @@ -135,8 +134,9 @@ void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta) #if 0 if (tb[TCA_STAB_DATA]) { - unsigned i, j, dlen; + unsigned int i, j, dlen; __u16 *data = RTA_DATA(tb[TCA_STAB_DATA]); + dlen = RTA_PAYLOAD(tb[TCA_STAB_DATA]) / sizeof(__u16); fprintf(fp, "\n%sstab data:", prefix); 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) ", diff --git a/tc/tc_util.h b/tc/tc_util.h index 61e60b1c..583a21a8 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -2,6 +2,7 @@ #define _TC_UTIL_H_ 1 #define MAX_MSG 16384 +#include <limits.h> #include <linux/pkt_sched.h> #include <linux/pkt_cls.h> #include <linux/gen_stats.h> @@ -22,89 +23,103 @@ enum struct qdisc_util { struct qdisc_util *next; const char *id; - 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); - int (*print_xstats)(struct qdisc_util *qu, FILE *f, struct rtattr *xstats); - - int (*parse_copt)(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n); - int (*print_copt)(struct qdisc_util *qu, FILE *f, struct rtattr *opt); + 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); + int (*print_xstats)(struct qdisc_util *qu, + FILE *f, struct rtattr *xstats); + + int (*parse_copt)(struct qdisc_util *qu, int argc, + char **argv, struct nlmsghdr *n); + int (*print_copt)(struct qdisc_util *qu, FILE *f, struct rtattr *opt); }; extern __u16 f_proto; struct filter_util { struct filter_util *next; - char id[16]; - int (*parse_fopt)(struct filter_util *qu, char *fhandle, int argc, - char **argv, struct nlmsghdr *n); - int (*print_fopt)(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle); + char id[16]; + int (*parse_fopt)(struct filter_util *qu, char *fhandle, + int argc, char **argv, struct nlmsghdr *n); + 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); + 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); }; struct exec_util { - struct exec_util *next; - char id[16]; - int (*parse_eopt)(struct exec_util *eu, int argc, char **argv); + struct exec_util *next; + char id[16]; + int (*parse_eopt)(struct exec_util *eu, int argc, char **argv); }; -extern const char *get_tc_lib(void); - -extern struct qdisc_util *get_qdisc_kind(const char *str); -extern struct filter_util *get_filter_kind(const char *str); - -extern int get_qdisc_handle(__u32 *h, const char *str); -extern int get_rate(unsigned *rate, const char *str); -extern int get_rate64(__u64 *rate, const char *str); -extern int get_size(unsigned *size, const char *str); -extern int get_size_and_cell(unsigned *size, int *cell_log, char *str); -extern int get_time(unsigned *time, const char *str); -extern int get_linklayer(unsigned *val, const char *arg); - -extern void print_rate(char *buf, int len, __u64 rate); -extern void print_size(char *buf, int len, __u32 size); -extern void print_qdisc_handle(char *buf, int len, __u32 h); -extern void print_time(char *buf, int len, __u32 time); -extern void print_linklayer(char *buf, int len, unsigned linklayer); - -extern char * sprint_rate(__u64 rate, char *buf); -extern char * sprint_size(__u32 size, char *buf); -extern char * sprint_qdisc_handle(__u32 h, char *buf); -extern char * sprint_tc_classid(__u32 h, char *buf); -extern char * sprint_time(__u32 time, char *buf); -extern char * sprint_ticks(__u32 ticks, char *buf); -extern char * sprint_linklayer(unsigned linklayer, char *buf); - -extern void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtattr **xstats); -extern void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats); - -extern int get_tc_classid(__u32 *h, const char *str); -extern int print_tc_classid(char *buf, int len, __u32 h); -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, const struct rtattr *tb); -extern int tc_print_ipt(FILE *f, const struct rtattr *tb); -extern int parse_action(int *, char ***, int, struct nlmsghdr *); -extern void print_tm(FILE *f, const struct tcf_t *tm); -extern int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt); - -extern int cls_names_init(char *path); -extern void cls_names_uninit(void); +const char *get_tc_lib(void); + +struct qdisc_util *get_qdisc_kind(const char *str); +struct filter_util *get_filter_kind(const char *str); + +int get_qdisc_handle(__u32 *h, const char *str); +int get_rate(unsigned int *rate, const char *str); +int get_rate64(__u64 *rate, const char *str); +int get_size(unsigned int *size, const char *str); +int get_size_and_cell(unsigned int *size, int *cell_log, char *str); +int get_time(unsigned int *time, const char *str); +int get_linklayer(unsigned int *val, const char *arg); + +void print_rate(char *buf, int len, __u64 rate); +void print_size(char *buf, int len, __u32 size); +void print_qdisc_handle(char *buf, int len, __u32 h); +void print_time(char *buf, int len, __u32 time); +void print_linklayer(char *buf, int len, unsigned int linklayer); + +char *sprint_rate(__u64 rate, char *buf); +char *sprint_size(__u32 size, char *buf); +char *sprint_qdisc_handle(__u32 h, char *buf); +char *sprint_tc_classid(__u32 h, char *buf); +char *sprint_time(__u32 time, char *buf); +char *sprint_ticks(__u32 ticks, char *buf); +char *sprint_linklayer(unsigned int linklayer, char *buf); + +void print_tcstats_attr(FILE *fp, struct rtattr *tb[], + char *prefix, struct rtattr **xstats); +void print_tcstats2_attr(FILE *fp, struct rtattr *rta, + char *prefix, struct rtattr **xstats); + +int get_tc_classid(__u32 *h, const char *str); +int print_tc_classid(char *buf, int len, __u32 h); +char *sprint_tc_classid(__u32 h, char *buf); + +int tc_print_police(FILE *f, struct rtattr *tb); +int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); + +int parse_action_control(int *argc_p, char ***argv_p, + int *result_p, bool allow_num); +void parse_action_control_dflt(int *argc_p, char ***argv_p, + int *result_p, bool allow_num, + int default_result); +int parse_action_control_slash(int *argc_p, char ***argv_p, + int *result1_p, int *result2_p, bool allow_num); +void print_action_control(FILE *f, const char *prefix, + int action, const char *suffix); +int act_parse_police(struct action_util *a, int *argc_p, + char ***argv_p, int tca_id, struct nlmsghdr *n); +int print_police(struct action_util *a, FILE *f, struct rtattr *tb); +int police_print_xstats(struct action_util *a, FILE *f, struct rtattr *tb); +int tc_print_action(FILE *f, const struct rtattr *tb, unsigned short tot_acts); +int tc_print_ipt(FILE *f, const struct rtattr *tb); +int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); +void print_tm(FILE *f, const struct tcf_t *tm); +int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt); + +int cls_names_init(char *path); +void cls_names_uninit(void); #endif |