aboutsummaryrefslogtreecommitdiffstats
path: root/tc
diff options
context:
space:
mode:
Diffstat (limited to 'tc')
-rw-r--r--tc/Android.mk2
-rw-r--r--tc/Makefile70
-rw-r--r--tc/e_bpf.c9
-rw-r--r--tc/em_canid.c4
-rw-r--r--tc/em_cmp.c6
-rw-r--r--tc/em_ipset.c54
-rw-r--r--tc/em_meta.c34
-rw-r--r--tc/em_nbyte.c6
-rw-r--r--tc/em_u32.c7
-rw-r--r--tc/f_basic.c11
-rw-r--r--tc/f_bpf.c102
-rw-r--r--tc/f_cgroup.c6
-rw-r--r--tc/f_flow.c10
-rw-r--r--tc/f_flower.c1002
-rw-r--r--tc/f_fw.c40
-rw-r--r--tc/f_matchall.c157
-rw-r--r--tc/f_route.c16
-rw-r--r--tc/f_rsvp.c30
-rw-r--r--tc/f_tcindex.c82
-rw-r--r--tc/f_u32.c210
-rw-r--r--tc/m_action.c301
-rw-r--r--tc/m_bpf.c93
-rw-r--r--tc/m_connmark.c34
-rw-r--r--tc/m_csum.c59
-rw-r--r--tc/m_ematch.c18
-rw-r--r--tc/m_estimator.c2
-rw-r--r--tc/m_gact.c102
-rw-r--r--tc/m_ife.c336
-rw-r--r--tc/m_ipt.c233
-rw-r--r--tc/m_mirred.c101
-rw-r--r--tc/m_nat.c50
-rw-r--r--tc/m_pedit.c553
-rw-r--r--tc/m_pedit.h62
-rw-r--r--tc/m_police.c185
-rw-r--r--tc/m_sample.c184
-rw-r--r--tc/m_simple.c40
-rw-r--r--tc/m_skbedit.c80
-rw-r--r--tc/m_skbmod.c236
-rw-r--r--tc/m_tunnel_key.c315
-rw-r--r--tc/m_vlan.c96
-rw-r--r--tc/m_xt.c254
-rw-r--r--tc/m_xt_old.c129
-rw-r--r--tc/p_eth.c75
-rw-r--r--tc/p_icmp.c5
-rw-r--r--tc/p_ip.c68
-rw-r--r--tc/p_ip6.c91
-rw-r--r--tc/p_tcp.c40
-rw-r--r--tc/p_udp.c33
-rw-r--r--tc/q_atm.c119
-rw-r--r--tc/q_cbq.c88
-rw-r--r--tc/q_choke.c10
-rw-r--r--tc/q_clsact.c1
-rw-r--r--tc/q_codel.c25
-rw-r--r--tc/q_drr.c2
-rw-r--r--tc/q_dsmark.c65
-rw-r--r--tc/q_fifo.c5
-rw-r--r--tc/q_fq.c24
-rw-r--r--tc/q_fq_codel.c55
-rw-r--r--tc/q_gred.c53
-rw-r--r--tc/q_hfsc.c18
-rw-r--r--tc/q_hhf.c29
-rw-r--r--tc/q_htb.c61
-rw-r--r--tc/q_ingress.c1
-rw-r--r--tc/q_mqprio.c10
-rw-r--r--tc/q_multiq.c4
-rw-r--r--tc/q_netem.c52
-rw-r--r--tc/q_pie.c11
-rw-r--r--tc/q_prio.c11
-rw-r--r--tc/q_qfq.c13
-rw-r--r--tc/q_red.c11
-rw-r--r--tc/q_rr.c9
-rw-r--r--tc/q_sfb.c20
-rw-r--r--tc/q_sfq.c5
-rw-r--r--tc/q_tbf.c36
-rw-r--r--tc/tc.c44
-rw-r--r--tc/tc_bpf.c1892
-rw-r--r--tc/tc_bpf.h79
-rw-r--r--tc/tc_cbq.c9
-rw-r--r--tc/tc_class.c54
-rw-r--r--tc/tc_core.c38
-rw-r--r--tc/tc_estimator.c9
-rw-r--r--tc/tc_exec.c12
-rw-r--r--tc/tc_filter.c394
-rw-r--r--tc/tc_monitor.c6
-rw-r--r--tc/tc_qdisc.c127
-rw-r--r--tc/tc_red.c20
-rw-r--r--tc/tc_stab.c12
-rw-r--r--tc/tc_util.c307
-rw-r--r--tc/tc_util.h157
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
diff --git a/tc/e_bpf.c b/tc/e_bpf.c
index 2d650a46..84f43e6c 100644
--- a/tc/e_bpf.c
+++ b/tc/e_bpf.c
@@ -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;
diff --git a/tc/f_bpf.c b/tc/f_bpf.c
index afc2e582..3f619d0d 100644
--- a/tc/f_bpf.c
+++ b/tc/f_bpf.c
@@ -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, &eth_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;
}
diff --git a/tc/f_fw.c b/tc/f_fw.c
index 165f4896..c39789b3 100644
--- a/tc/f_fw.c
+++ b/tc/f_fw.c
@@ -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;
}
diff --git a/tc/f_u32.c b/tc/f_u32.c
index 0b976789..14b95889 100644
--- a/tc/f_u32.c
+++ b/tc/f_u32.c
@@ -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;
diff --git a/tc/m_bpf.c b/tc/m_bpf.c
index c5e2fa5b..e3d0a2b1 100644
--- a/tc/m_bpf.c
+++ b/tc/m_bpf.c
@@ -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,
+};
diff --git a/tc/m_ipt.c b/tc/m_ipt.c
index 948becbc..1b935ec0 100644
--- a/tc/m_ipt.c
+++ b/tc/m_ipt.c
@@ -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 ");
diff --git a/tc/m_nat.c b/tc/m_nat.c
index d502a819..31b68fb6 100644
--- a/tc/m_nat.c
+++ b/tc/m_nat.c
@@ -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);
}
}
diff --git a/tc/m_xt.c b/tc/m_xt.c
index bf603fcb..9218b145 100644
--- a/tc/m_xt.c
+++ b/tc/m_xt.c
@@ -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
diff --git a/tc/p_ip.c b/tc/p_ip.c
index 08fdbaa4..0272a6ea 100644
--- a/tc/p_ip.c
+++ b/tc/p_ip.c
@@ -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,
+};
diff --git a/tc/p_tcp.c b/tc/p_tcp.c
index 32ffc027..cf14574c 100644
--- a/tc/p_tcp.c
+++ b/tc/p_tcp.c
@@ -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 = {
diff --git a/tc/p_udp.c b/tc/p_udp.c
index 2b9b88fc..3916d958 100644
--- a/tc/p_udp.c
+++ b/tc/p_udp.c
@@ -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;
}
diff --git a/tc/q_atm.c b/tc/q_atm.c
index 2598e298..56e7ad80 100644
--- a/tc/q_atm.c
+++ b/tc/q_atm.c
@@ -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,
diff --git a/tc/q_cbq.c b/tc/q_cbq.c
index 38a61630..f148175c 100644
--- a/tc/q_cbq.c
+++ b/tc/q_cbq.c
@@ -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;
}
diff --git a/tc/q_drr.c b/tc/q_drr.c
index 746736dd..79c81a22 100644
--- a/tc/q_drr.c
+++ b/tc/q_drr.c
@@ -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) {
diff --git a/tc/q_fq.c b/tc/q_fq.c
index 2a370b36..45b2ffd9 100644
--- a/tc/q_fq.c
+++ b/tc/q_fq.c
@@ -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;
}
diff --git a/tc/q_hhf.c b/tc/q_hhf.c
index 06ec8a28..738b5636 100644
--- a/tc/q_hhf.c
+++ b/tc/q_hhf.c
@@ -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)
diff --git a/tc/q_htb.c b/tc/q_htb.c
index 7075a4c0..a811c284 100644
--- a/tc/q_htb.c
+++ b/tc/q_htb.c
@@ -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,
};
diff --git a/tc/q_pie.c b/tc/q_pie.c
index 193b05de..a697db75 100644
--- a/tc/q_pie.c
+++ b/tc/q_pie.c
@@ -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,
};
diff --git a/tc/q_qfq.c b/tc/q_qfq.c
index 05b4d84e..0e026749 100644
--- a/tc/q_qfq.c
+++ b/tc/q_qfq.c
@@ -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;
diff --git a/tc/q_red.c b/tc/q_red.c
index abd86c7b..ec706aaf 100644
--- a/tc/q_red.c
+++ b/tc/q_red.c
@@ -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);
diff --git a/tc/q_rr.c b/tc/q_rr.c
index e8a91652..f330311d 100644
--- a/tc/q_rr.c
+++ b/tc/q_rr.c
@@ -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,
};
diff --git a/tc/q_sfb.c b/tc/q_sfb.c
index f11c33aa..05c5f132 100644
--- a/tc/q_sfb.c
+++ b/tc/q_sfb.c
@@ -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,
diff --git a/tc/q_sfq.c b/tc/q_sfq.c
index 50846a98..b5a98950 100644
--- a/tc/q_sfq.c
+++ b/tc/q_sfq.c
@@ -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);
diff --git a/tc/q_tbf.c b/tc/q_tbf.c
index 0981e6f7..18b2193b 100644
--- a/tc/q_tbf.c
+++ b/tc/q_tbf.c
@@ -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;
}
diff --git a/tc/tc.c b/tc/tc.c
index e1d4bc32..82a30042 100644
--- a/tc/tc.c
+++ b/tc/tc.c
@@ -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, &section, 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, &section, 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