diff options
Diffstat (limited to 'lib/route/cls')
-rw-r--r-- | lib/route/cls/.gitignore | 2 | ||||
-rw-r--r-- | lib/route/cls/basic.c | 10 | ||||
-rw-r--r-- | lib/route/cls/cgroup.c | 23 | ||||
-rw-r--r-- | lib/route/cls/ematch.c | 12 | ||||
-rw-r--r-- | lib/route/cls/ematch/cmp.c | 8 | ||||
-rw-r--r-- | lib/route/cls/ematch/container.c | 8 | ||||
-rw-r--r-- | lib/route/cls/ematch/meta.c | 12 | ||||
-rw-r--r-- | lib/route/cls/ematch/nbyte.c | 8 | ||||
-rw-r--r-- | lib/route/cls/ematch/text.c | 12 | ||||
-rw-r--r-- | lib/route/cls/ematch_grammar.l | 8 | ||||
-rw-r--r-- | lib/route/cls/ematch_syntax.y | 9 | ||||
-rw-r--r-- | lib/route/cls/flower.c | 896 | ||||
-rw-r--r-- | lib/route/cls/fw.c | 13 | ||||
-rw-r--r-- | lib/route/cls/mall.c | 18 | ||||
-rw-r--r-- | lib/route/cls/police.c | 8 | ||||
-rw-r--r-- | lib/route/cls/u32.c | 124 |
16 files changed, 1027 insertions, 144 deletions
diff --git a/lib/route/cls/.gitignore b/lib/route/cls/.gitignore deleted file mode 100644 index 30f4521a..00000000 --- a/lib/route/cls/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -ematch_syntax.[ch] -ematch_grammar.[ch] diff --git a/lib/route/cls/basic.c b/lib/route/cls/basic.c index 3581c60f..93bf75d3 100644 --- a/lib/route/cls/basic.c +++ b/lib/route/cls/basic.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/basic.c Basic Classifier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2008-2013 Thomas Graf <tgraf@suug.ch> */ @@ -93,7 +87,7 @@ static int basic_msg_parser(struct rtnl_tc *tc, void *data) if (tb[TCA_BASIC_ACT]) { b->b_mask |= BASIC_ATTR_ACTION; err = rtnl_act_parse(&b->b_act, tb[TCA_BASIC_ACT]); - if (err) + if (err < 0) return err; } diff --git a/lib/route/cls/cgroup.c b/lib/route/cls/cgroup.c index b1452618..ff993d18 100644 --- a/lib/route/cls/cgroup.c +++ b/lib/route/cls/cgroup.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/cgroup.c Control Groups Classifier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2009-2013 Thomas Graf <tgraf@suug.ch> */ @@ -36,17 +30,14 @@ static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = { static int cgroup_clone(void *_dst, void *_src) { - struct rtnl_cgroup *dst = NULL, *src = _src; + struct rtnl_cgroup *dst = _dst, *src = _src; - dst = calloc(1, sizeof(*dst)); - if (!dst) - return -NLE_NOMEM; + dst->cg_ematch = NULL; - dst->cg_mask = src->cg_mask; - dst->cg_ematch = rtnl_ematch_tree_clone(src->cg_ematch); - if (!dst) { - free(dst); - return -NLE_NOMEM; + if (src->cg_ematch) { + dst->cg_ematch = rtnl_ematch_tree_clone(src->cg_ematch); + if (!dst->cg_ematch) + return -NLE_NOMEM; } return 0; diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c index 18f5be9f..90520302 100644 --- a/lib/route/cls/ematch.c +++ b/lib/route/cls/ematch.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/ematch.c Extended Matches - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2008-2013 Thomas Graf <tgraf@suug.ch> */ @@ -699,14 +693,14 @@ int rtnl_ematch_parse_expr(const char *expr, char **errp, if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID))) return -NLE_FAILURE; - if ((err = ematch_lex_init(&scanner)) < 0) { + if (ematch_lex_init(&scanner) < 0) { err = -NLE_FAILURE; goto errout; } buf = ematch__scan_string(expr, scanner); - if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) { + if (ematch_parse(scanner, errp, &tree->et_list) != 0) { ematch__delete_buffer(buf, scanner); err = -NLE_PARSE_ERR; goto errout; diff --git a/lib/route/cls/ematch/cmp.c b/lib/route/cls/ematch/cmp.c index 2e380c39..f5758669 100644 --- a/lib/route/cls/ematch/cmp.c +++ b/lib/route/cls/ematch/cmp.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/ematch/cmp.c Simple packet data comparison ematch - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2008-2013 Thomas Graf <tgraf@suug.ch> */ diff --git a/lib/route/cls/ematch/container.c b/lib/route/cls/ematch/container.c index 813391ab..b23169bb 100644 --- a/lib/route/cls/ematch/container.c +++ b/lib/route/cls/ematch/container.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/ematch/container.c Container Ematch - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2008-2013 Thomas Graf <tgraf@suug.ch> */ diff --git a/lib/route/cls/ematch/meta.c b/lib/route/cls/ematch/meta.c index a26ed4c8..3f63cdea 100644 --- a/lib/route/cls/ematch/meta.c +++ b/lib/route/cls/ematch/meta.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/ematch/meta.c Metadata Match - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch> */ @@ -246,9 +240,9 @@ static void dump_value(struct rtnl_meta_value *v, struct nl_dump_params *p) nl_dump(p, " >> %u", v->mv_shift); if (v->mv_len == 4) - nl_dump(p, " & %#x", *(uint32_t *) (v + 1)); + nl_dump(p, " & %#lx", (long unsigned) *(uint32_t *) (v + 1)); else if (v->mv_len == 8) - nl_dump(p, " & %#x", *(uint64_t *) (v + 1)); + nl_dump(p, " & %#llx", (long long unsigned) (*(uint64_t *) (v + 1))); } break; diff --git a/lib/route/cls/ematch/nbyte.c b/lib/route/cls/ematch/nbyte.c index 2942c0da..735dfc86 100644 --- a/lib/route/cls/ematch/nbyte.c +++ b/lib/route/cls/ematch/nbyte.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/ematch/nbyte.c Nbyte comparison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch> */ diff --git a/lib/route/cls/ematch/text.c b/lib/route/cls/ematch/text.c index 4dcd4f05..b5248332 100644 --- a/lib/route/cls/ematch/text.c +++ b/lib/route/cls/ematch/text.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/ematch/text.c Text Search - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch> */ @@ -17,6 +11,7 @@ */ #include <netlink-private/netlink.h> +#include <netlink-private/utils.h> #include <netlink-private/tc.h> #include <netlink/netlink.h> #include <netlink/route/cls/ematch.h> @@ -91,8 +86,7 @@ void rtnl_ematch_text_set_algo(struct rtnl_ematch *e, const char *algo) { struct text_data *t = rtnl_ematch_data(e); - strncpy(t->cfg.algo, algo, sizeof(t->cfg.algo)); - t->cfg.algo[sizeof(t->cfg.algo) - 1] = '\0'; + _nl_strncpy_trunc(t->cfg.algo, algo, sizeof(t->cfg.algo)); } char *rtnl_ematch_text_get_algo(struct rtnl_ematch *e) diff --git a/lib/route/cls/ematch_grammar.l b/lib/route/cls/ematch_grammar.l index e97f9fef..4f57951e 100644 --- a/lib/route/cls/ematch_grammar.l +++ b/lib/route/cls/ematch_grammar.l @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/ematch_grammar.l ematch expression grammar - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch> */ diff --git a/lib/route/cls/ematch_syntax.y b/lib/route/cls/ematch_syntax.y index 82d753d2..0c89603f 100644 --- a/lib/route/cls/ematch_syntax.y +++ b/lib/route/cls/ematch_syntax.y @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/ematch_syntax.y ematch expression syntax - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch> */ @@ -52,6 +46,7 @@ %{ extern int ematch_lex(YYSTYPE *, void *); +#define ematch_error yyerror static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const char *msg) { if (msg) diff --git a/lib/route/cls/flower.c b/lib/route/cls/flower.c new file mode 100644 index 00000000..11bd7095 --- /dev/null +++ b/lib/route/cls/flower.c @@ -0,0 +1,896 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/* + * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com> + */ + +#include <netlink-private/netlink.h> +#include <netlink-private/tc.h> +#include <netlink/netlink.h> +#include <netlink/attr.h> +#include <netlink/utils.h> +#include <netlink-private/route/tc-api.h> +#include <netlink/route/classifier.h> +#include <netlink/route/action.h> +#include <netlink/route/cls/flower.h> + + +/** @cond SKIP */ +#define FLOWER_ATTR_FLAGS (1 << 0) +#define FLOWER_ATTR_ACTION (1 << 1) +#define FLOWER_ATTR_VLAN_ID (1 << 2) +#define FLOWER_ATTR_VLAN_PRIO (1 << 3) +#define FLOWER_ATTR_VLAN_ETH_TYPE (1 << 4) +#define FLOWER_ATTR_DST_MAC (1 << 5) +#define FLOWER_ATTR_DST_MAC_MASK (1 << 6) +#define FLOWER_ATTR_SRC_MAC (1 << 7) +#define FLOWER_ATTR_SRC_MAC_MASK (1 << 8) +#define FLOWER_ATTR_IP_DSCP (1 << 9) +#define FLOWER_ATTR_IP_DSCP_MASK (1 << 10) +#define FLOWER_ATTR_PROTO (1 << 11) +#define FLOWER_ATTR_IPV4_SRC (1 << 12) +#define FLOWER_ATTR_IPV4_SRC_MASK (1 << 13) +#define FLOWER_ATTR_IPV4_DST (1 << 14) +#define FLOWER_ATTR_IPV4_DST_MASK (1 << 15) +/** @endcond */ + +#define FLOWER_DSCP_MAX 0xe0 +#define FLOWER_DSCP_MASK_MAX 0xe0 +#define FLOWER_VID_MAX 4095 +#define FLOWER_VLAN_PRIO_MAX 7 + +static struct nla_policy flower_policy[TCA_FLOWER_MAX + 1] = { + [TCA_FLOWER_FLAGS] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_ETH_DST] = { .maxlen = ETH_ALEN }, + [TCA_FLOWER_KEY_ETH_DST_MASK] = { .maxlen = ETH_ALEN }, + [TCA_FLOWER_KEY_ETH_SRC] = { .maxlen = ETH_ALEN }, + [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .maxlen = ETH_ALEN }, + [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 }, + [TCA_FLOWER_KEY_IP_TOS] = { .type = NLA_U8 }, + [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 }, + [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, +}; + +static int flower_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_flower *f = data; + struct nlattr *tb[TCA_FLOWER_MAX + 1]; + int err; + + err = tca_parse(tb, TCA_FLOWER_MAX, tc, flower_policy); + if (err < 0) + return err; + + if (tb[TCA_FLOWER_FLAGS]) { + f->cf_flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); + f->cf_mask |= FLOWER_ATTR_FLAGS; + } + + if (tb[TCA_FLOWER_ACT]) { + err = rtnl_act_parse(&f->cf_act, tb[TCA_FLOWER_ACT]); + if (err) + return err; + + f->cf_mask |= FLOWER_ATTR_ACTION; + } + + if (tb[TCA_FLOWER_KEY_ETH_TYPE]) { + f->cf_proto = nla_get_u16(tb[TCA_FLOWER_KEY_ETH_TYPE]); + f->cf_mask |= FLOWER_ATTR_PROTO; + } + + if (tb[TCA_FLOWER_KEY_VLAN_ID]) { + f->cf_vlan_id = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]); + f->cf_mask |= FLOWER_ATTR_VLAN_ID; + } + + if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) { + f->cf_vlan_prio = nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]); + f->cf_mask |= FLOWER_ATTR_VLAN_PRIO; + } + + if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) { + f->cf_vlan_ethtype = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]); + f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE; + } + + if (tb[TCA_FLOWER_KEY_ETH_DST]) { + nla_memcpy(f->cf_dst_mac, tb[TCA_FLOWER_KEY_ETH_DST], ETH_ALEN); + f->cf_mask |= FLOWER_ATTR_DST_MAC; + } + + if (tb[TCA_FLOWER_KEY_ETH_DST_MASK]) { + nla_memcpy(f->cf_dst_mac_mask, tb[TCA_FLOWER_KEY_ETH_DST_MASK], ETH_ALEN); + f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK; + } + + if (tb[TCA_FLOWER_KEY_ETH_SRC]) { + nla_memcpy(f->cf_src_mac, tb[TCA_FLOWER_KEY_ETH_SRC], ETH_ALEN); + f->cf_mask |= FLOWER_ATTR_SRC_MAC; + } + + if (tb[TCA_FLOWER_KEY_ETH_SRC_MASK]) { + nla_memcpy(f->cf_src_mac_mask, tb[TCA_FLOWER_KEY_ETH_SRC_MASK], ETH_ALEN); + f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK; + } + + if (tb[TCA_FLOWER_KEY_IP_TOS]) { + f->cf_ip_dscp = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS]); + f->cf_mask |= FLOWER_ATTR_IP_DSCP; + } + + if (tb[TCA_FLOWER_KEY_IP_TOS_MASK]) { + f->cf_ip_dscp_mask = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS_MASK]); + f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK; + } + + if (tb[TCA_FLOWER_KEY_IPV4_SRC]) { + f->cf_ipv4_src = nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_SRC]); + f->cf_mask |= FLOWER_ATTR_IPV4_SRC; + } + + if (tb[TCA_FLOWER_KEY_IPV4_SRC_MASK]) { + f->cf_ipv4_src_mask = + nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_SRC_MASK]); + f->cf_mask |= FLOWER_ATTR_IPV4_SRC_MASK; + } + + if (tb[TCA_FLOWER_KEY_IPV4_DST]) { + f->cf_ipv4_dst = nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_DST]); + f->cf_mask |= FLOWER_ATTR_IPV4_DST; + } + + if (tb[TCA_FLOWER_KEY_IPV4_DST_MASK]) { + f->cf_ipv4_dst_mask = + nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_DST_MASK]); + f->cf_mask |= FLOWER_ATTR_IPV4_DST_MASK; + } + + return 0; +} + +static int flower_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_flower *f = data; + int err; + + if (!f) + return 0; + + if (f->cf_mask & FLOWER_ATTR_FLAGS) + NLA_PUT_U32(msg, TCA_FLOWER_FLAGS, f->cf_flags); + + if (f->cf_mask & FLOWER_ATTR_ACTION) { + err = rtnl_act_fill(msg, TCA_FLOWER_ACT, f->cf_act); + if (err) + return err; + } + + if (f->cf_mask & FLOWER_ATTR_PROTO) + NLA_PUT_U16(msg, TCA_FLOWER_KEY_ETH_TYPE, f->cf_proto); + + if (f->cf_mask & FLOWER_ATTR_VLAN_ID) + NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ID, f->cf_vlan_id); + + if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO) + NLA_PUT_U8(msg, TCA_FLOWER_KEY_VLAN_PRIO, f->cf_vlan_prio); + + if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE) + NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ETH_TYPE, f->cf_vlan_ethtype); + + if (f->cf_mask & FLOWER_ATTR_DST_MAC) + NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST, ETH_ALEN, f->cf_dst_mac); + + if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK) + NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST_MASK, ETH_ALEN, f->cf_dst_mac_mask); + + if (f->cf_mask & FLOWER_ATTR_SRC_MAC) + NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC, ETH_ALEN, f->cf_src_mac); + + if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK) + NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC_MASK, ETH_ALEN, f->cf_src_mac_mask); + + if (f->cf_mask & FLOWER_ATTR_IP_DSCP) + NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS, f->cf_ip_dscp); + + if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK) + NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS_MASK, f->cf_ip_dscp_mask); + + if (f->cf_mask & FLOWER_ATTR_IPV4_SRC) + NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_SRC, f->cf_ipv4_src); + + if (f->cf_mask & FLOWER_ATTR_IPV4_SRC_MASK) + NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_SRC_MASK, + f->cf_ipv4_src_mask); + + if (f->cf_mask & FLOWER_ATTR_IPV4_DST) + NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_DST, f->cf_ipv4_dst); + + if (f->cf_mask & FLOWER_ATTR_IPV4_DST_MASK) + NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_DST_MASK, + f->cf_ipv4_dst_mask); + + return 0; + +nla_put_failure: + return -NLE_NOMEM; +} + +static void flower_free_data(struct rtnl_tc *tc, void *data) +{ + struct rtnl_flower *f = data; + + if (f->cf_act) + rtnl_act_put_all(&f->cf_act); +} + +static int flower_clone(void *_dst, void *_src) +{ + struct rtnl_flower *dst = _dst, *src = _src; + + if (src->cf_act) { + if (!(dst->cf_act = rtnl_act_alloc())) + return -NLE_NOMEM; + + memcpy(dst->cf_act, src->cf_act, sizeof(struct rtnl_act)); + + /* action nl list next and prev pointers must be updated */ + nl_init_list_head(&dst->cf_act->ce_list); + + if ( src->cf_act->c_opts + && !(dst->cf_act->c_opts = nl_data_clone(src->cf_act->c_opts))) + return -NLE_NOMEM; + + if ( src->cf_act->c_xstats + && !(dst->cf_act->c_xstats = nl_data_clone(src->cf_act->c_xstats))) + return -NLE_NOMEM; + + if ( src->cf_act->c_subdata + && !(dst->cf_act->c_subdata = nl_data_clone(src->cf_act->c_subdata))) + return -NLE_NOMEM; + + if (dst->cf_act->c_link) { + nl_object_get(OBJ_CAST(dst->cf_act->c_link)); + } + + dst->cf_act->a_next = NULL; /* Only clone first in chain */ + } + + return 0; +} + +static void flower_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_flower *f = data; + char addr_str[INET_ADDRSTRLEN]; + char mask_str[INET_ADDRSTRLEN]; + + if (!f) + return; + + if (f->cf_mask & FLOWER_ATTR_FLAGS) + nl_dump(p, " flags %u", f->cf_flags); + + if (f->cf_mask & FLOWER_ATTR_PROTO) + nl_dump(p, " protocol %u", f->cf_proto); + + if (f->cf_mask & FLOWER_ATTR_VLAN_ID) + nl_dump(p, " vlan_id %u", f->cf_vlan_id); + + if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO) + nl_dump(p, " vlan_prio %u", f->cf_vlan_prio); + + if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE) + nl_dump(p, " vlan_ethtype %u", f->cf_vlan_ethtype); + + if (f->cf_mask & FLOWER_ATTR_DST_MAC) + nl_dump(p, " dst_mac %02x:%02x:%02x:%02x:%02x:%02x", + f->cf_dst_mac[0], f->cf_dst_mac[1], + f->cf_dst_mac[2], f->cf_dst_mac[3], + f->cf_dst_mac[4], f->cf_dst_mac[5]); + + if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK) + nl_dump(p, " dst_mac_mask %02x:%02x:%02x:%02x:%02x:%02x", + f->cf_dst_mac_mask[0], f->cf_dst_mac_mask[1], + f->cf_dst_mac_mask[2], f->cf_dst_mac_mask[3], + f->cf_dst_mac_mask[4], f->cf_dst_mac_mask[5]); + + if (f->cf_mask & FLOWER_ATTR_SRC_MAC) + nl_dump(p, " src_mac %02x:%02x:%02x:%02x:%02x:%02x", + f->cf_src_mac[0], f->cf_src_mac[1], + f->cf_src_mac[2], f->cf_src_mac[3], + f->cf_src_mac[4], f->cf_src_mac[5]); + + if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK) + nl_dump(p, " src_mac_mask %02x:%02x:%02x:%02x:%02x:%02x", + f->cf_src_mac_mask[0], f->cf_src_mac_mask[1], + f->cf_src_mac_mask[2], f->cf_src_mac_mask[3], + f->cf_src_mac_mask[4], f->cf_src_mac_mask[5]); + + if (f->cf_mask & FLOWER_ATTR_IP_DSCP) + nl_dump(p, " dscp %u", f->cf_ip_dscp); + + if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK) + nl_dump(p, " dscp_mask %u", f->cf_ip_dscp_mask); + + if (f->cf_mask & FLOWER_ATTR_IPV4_SRC) { + inet_ntop(AF_INET, &f->cf_ipv4_src, addr_str, sizeof(addr_str)); + inet_ntop(AF_INET, &f->cf_ipv4_src_mask, mask_str, sizeof(mask_str)); + nl_dump(p, "IPv4 src %s mask %s\n", addr_str, mask_str); + } + + if (f->cf_mask & FLOWER_ATTR_IPV4_DST) { + inet_ntop(AF_INET, &f->cf_ipv4_dst, addr_str, sizeof(addr_str)); + inet_ntop(AF_INET, &f->cf_ipv4_dst_mask, mask_str, sizeof(mask_str)); + nl_dump(p, "IPv4 dst %s mask %s\n", addr_str, mask_str); + } +} + +/** + * @name Attribute Modification + * @{ + */ + +/** + * Set protocol for flower classifier + * @arg cls Flower classifier. + * @arg proto protocol (ETH_P_*) + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_proto(struct rtnl_cls *cls, uint16_t proto) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + f->cf_proto = htons(proto); + f->cf_mask |= FLOWER_ATTR_PROTO; + + return 0; +} + +/** + * Get protocol for flower classifier + * @arg cls Flower classifier. + * @arg proto protocol + * @return 0 on success or a negative error code. +*/ +int rtnl_flower_get_proto(struct rtnl_cls *cls, uint16_t *proto) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return -NLE_INVAL; + + if (!(f->cf_mask & FLOWER_ATTR_PROTO)) + return -NLE_MISSING_ATTR; + + *proto = ntohs(f->cf_proto); + + return 0; +} + +/** + * Set vlan id for flower classifier + * @arg cls Flower classifier. + * @arg vid vlan id + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_vlan_id(struct rtnl_cls *cls, uint16_t vid) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (vid > FLOWER_VID_MAX) + return -NLE_RANGE; + + f->cf_vlan_id = vid; + f->cf_mask |= FLOWER_ATTR_VLAN_ID; + + return 0; +} + +/** + * Get vlan id for flower classifier + * @arg cls Flower classifier. + * @arg vid vlan id + * @return 0 on success or a negative error code. +*/ +int rtnl_flower_get_vlan_id(struct rtnl_cls *cls, uint16_t *vid) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return -NLE_INVAL; + + if (!(f->cf_mask & FLOWER_ATTR_VLAN_ID)) + return -NLE_MISSING_ATTR; + + *vid = f->cf_vlan_id; + + return 0; +} + +/** + * Set vlan priority for flower classifier + * @arg cls Flower classifier. + * @arg prio vlan priority + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_vlan_prio(struct rtnl_cls *cls, uint8_t prio) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (prio > FLOWER_VLAN_PRIO_MAX) + return -NLE_RANGE; + + f->cf_vlan_prio = prio; + f->cf_mask |= FLOWER_ATTR_VLAN_PRIO; + + return 0; +} + +/** + * Get vlan prio for flower classifier + * @arg cls Flower classifier. + * @arg prio vlan priority + * @return 0 on success or a negative error code. +*/ +int rtnl_flower_get_vlan_prio(struct rtnl_cls *cls, uint8_t *prio) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return -NLE_INVAL; + + if (!(f->cf_mask & FLOWER_ATTR_VLAN_PRIO)) + return -NLE_MISSING_ATTR; + + *prio = f->cf_vlan_prio; + + return 0; +} + +/** + * Set vlan ethertype for flower classifier + * @arg cls Flower classifier. + * @arg ethtype vlan ethertype + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_vlan_ethtype(struct rtnl_cls *cls, uint16_t ethtype) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (!(f->cf_mask & FLOWER_ATTR_PROTO)) + return -NLE_MISSING_ATTR; + + if (f->cf_proto != htons(ETH_P_8021Q)) + return -NLE_INVAL; + + f->cf_vlan_ethtype = htons(ethtype); + f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE; + + return 0; +} + +/** + * Set destination mac address for flower classifier + * @arg cls Flower classifier. + * @arg mac destination mac address + * @arg mask mask for mac address + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_dst_mac(struct rtnl_cls *cls, unsigned char *mac, + unsigned char *mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (mac) { + memcpy(f->cf_dst_mac, mac, ETH_ALEN); + f->cf_mask |= FLOWER_ATTR_DST_MAC; + + if (mask) { + memcpy(f->cf_dst_mac_mask, mask, ETH_ALEN); + f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK; + } + + return 0; + } + + return -NLE_FAILURE; +} + +/** + * Get destination mac address for flower classifier + * @arg cls Flower classifier. + * @arg mac destination mac address + * @arg mask mask for mac address + * @return 0 on success or a negative error code. +*/ +int rtnl_flower_get_dst_mac(struct rtnl_cls *cls, unsigned char *mac, + unsigned char *mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return -NLE_INVAL; + + if (!(f->cf_mask & FLOWER_ATTR_DST_MAC)) + return -NLE_MISSING_ATTR; + + if (mac) + memcpy(mac, f->cf_dst_mac, ETH_ALEN); + + if (mask) + memcpy(mask, f->cf_dst_mac_mask, ETH_ALEN); + + return 0; +} + +/** + * Set source mac address for flower classifier + * @arg cls Flower classifier. + * @arg mac source mac address + * @arg mask mask for mac address + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_src_mac(struct rtnl_cls *cls, unsigned char *mac, + unsigned char *mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (mac) { + memcpy(f->cf_src_mac, mac, ETH_ALEN); + f->cf_mask |= FLOWER_ATTR_SRC_MAC; + + if (mask) { + memcpy(f->cf_src_mac_mask, mask, ETH_ALEN); + f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK; + } + + return 0; + } + + return -NLE_FAILURE; +} + +/** + * Get source mac address for flower classifier + * @arg cls Flower classifier. + * @arg mac source mac address + * @arg mask mask for mac address + * @return 0 on success or a negative error code. +*/ +int rtnl_flower_get_src_mac(struct rtnl_cls *cls, unsigned char *mac, + unsigned char *mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return -NLE_INVAL; + + if (!(f->cf_mask & FLOWER_ATTR_SRC_MAC)) + return -NLE_MISSING_ATTR; + + if (mac) + memcpy(mac, f->cf_src_mac, ETH_ALEN); + + if (mask) + memcpy(mask, f->cf_src_mac_mask, ETH_ALEN); + + return 0; +} + +/** + * Set dscp value for flower classifier + * @arg cls Flower classifier. + * @arg dscp dscp value + * @arg mask mask for dscp value + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_ip_dscp(struct rtnl_cls *cls, uint8_t dscp, uint8_t mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (dscp > FLOWER_DSCP_MAX) + return -NLE_RANGE; + + if (mask > FLOWER_DSCP_MASK_MAX) + return -NLE_RANGE; + + f->cf_ip_dscp = dscp; + f->cf_mask |= FLOWER_ATTR_IP_DSCP; + + if (mask) { + f->cf_ip_dscp_mask = mask; + f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK; + } + + return 0; +} + +/** + * Get dscp value for flower classifier + * @arg cls Flower classifier. + * @arg dscp dscp value + * @arg mask mask for dscp value + * @return 0 on success or a negative error code. +*/ +int rtnl_flower_get_ip_dscp(struct rtnl_cls *cls, uint8_t *dscp, uint8_t *mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return -NLE_INVAL; + + if (!(f->cf_mask & FLOWER_ATTR_IP_DSCP)) + return -NLE_MISSING_ATTR; + + *dscp = f->cf_ip_dscp; + *mask = f->cf_ip_dscp_mask; + + return 0; +} + +/** + * Set IPv4 source address for flower classifier + * @arg cls Flower classifier. + * @arg addr IPv4 source address + * @arg mask mask for IPv4 source address + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_ipv4_src(struct rtnl_cls *cls, in_addr_t addr, + in_addr_t mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (addr) { + f->cf_ipv4_src = addr; + f->cf_mask |= FLOWER_ATTR_IPV4_SRC; + + if (mask) { + f->cf_ipv4_src_mask = mask; + f->cf_mask |= FLOWER_ATTR_IPV4_SRC_MASK; + } + + return 0; + } + + return -NLE_FAILURE; +} + +/** + * Get IPv4 source address for flower classifier + * @arg cls Flower classifier. + * @arg addr IPv4 source address + * @arg mask mask for IPv4 source address + * @return 0 on success or a negative error code. + */ +int rtnl_flower_get_ipv4_src(struct rtnl_cls *cls, in_addr_t *out_addr, + in_addr_t *out_mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return -NLE_INVAL; + + if (!(f->cf_mask & FLOWER_ATTR_IPV4_SRC)) + return -NLE_MISSING_ATTR; + + if (out_addr) + *out_addr = f->cf_ipv4_src; + + if (out_mask) { + if (f->cf_mask & FLOWER_ATTR_IPV4_SRC_MASK) + *out_mask = f->cf_ipv4_src_mask; + else + *out_mask = 0xffffffff; + } + + return 0; +} + +/** + * Set IPv4 destination address for flower classifier + * @arg cls Flower classifier. + * @arg addr IPv4 destination address + * @arg mask mask for IPv4 destination address + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_ipv4_dst(struct rtnl_cls *cls, in_addr_t addr, + in_addr_t mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (addr) { + f->cf_ipv4_dst = addr; + f->cf_mask |= FLOWER_ATTR_IPV4_DST; + + if (mask) { + f->cf_ipv4_dst_mask = mask; + f->cf_mask |= FLOWER_ATTR_IPV4_DST_MASK; + } + + return 0; + } + + return -NLE_FAILURE; +} + +/** + * Get IPv4 destination address for flower classifier + * @arg cls Flower classifier. + * @arg addr IPv4 destination address + * @arg mask mask for IPv4 destination address + * @return 0 on success or a negative error code. + */ +int rtnl_flower_get_ipv4_dst(struct rtnl_cls *cls, in_addr_t *out_addr, + in_addr_t *out_mask) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return -NLE_INVAL; + + if (!(f->cf_mask & FLOWER_ATTR_IPV4_DST)) + return -NLE_MISSING_ATTR; + + if (out_addr) + *out_addr = f->cf_ipv4_dst; + + if (out_mask) { + if (f->cf_mask & FLOWER_ATTR_IPV4_DST_MASK) + *out_mask = f->cf_ipv4_dst_mask; + else + *out_mask = 0xffffffff; + } + + return 0; +} + +/** + * Append action for flower classifier + * @arg cls Flower classifier. + * @arg act action to append + * @return 0 on success or a negative error code. + */ +int rtnl_flower_append_action(struct rtnl_cls *cls, struct rtnl_act *act) +{ + struct rtnl_flower *f; + + if (!act) + return 0; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + f->cf_mask |= FLOWER_ATTR_ACTION; + + rtnl_act_get(act); + return rtnl_act_append(&f->cf_act, act); +} + +/** + * Delete action from flower classifier + * @arg cls Flower classifier. + * @arg act action to delete + * @return 0 on success or a negative error code. + */ +int rtnl_flower_del_action(struct rtnl_cls *cls, struct rtnl_act *act) +{ + struct rtnl_flower *f; + int ret; + + if (!act) + return 0; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + if (!(f->cf_mask & FLOWER_ATTR_ACTION)) + return -NLE_INVAL; + + ret = rtnl_act_remove(&f->cf_act, act); + if (ret) + return ret; + + if (!f->cf_act) + f->cf_mask &= ~FLOWER_ATTR_ACTION; + rtnl_act_put(act); + + return 0; +} + +/** + * Get action from flower classifier + * @arg cls Flower classifier. + * @return action on success or NULL on error. + */ +struct rtnl_act* rtnl_flower_get_action(struct rtnl_cls *cls) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data_peek(TC_CAST(cls)))) + return NULL; + + if (!(f->cf_mask & FLOWER_ATTR_ACTION)) + return NULL; + + rtnl_act_get(f->cf_act); + + return f->cf_act; +} + +/** + * Set flags for flower classifier + * @arg cls Flower classifier. + * @arg flags (TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW) + * @return 0 on success or a negative error code. + */ +int rtnl_flower_set_flags(struct rtnl_cls *cls, int flags) +{ + struct rtnl_flower *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + f->cf_flags = flags; + f->cf_mask |= FLOWER_ATTR_FLAGS; + + return 0; +} + +/** @} */ + +static struct rtnl_tc_ops flower_ops = { + .to_kind = "flower", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_flower), + .to_msg_parser = flower_msg_parser, + .to_free_data = flower_free_data, + .to_clone = flower_clone, + .to_msg_fill = flower_msg_fill, + .to_dump = { + [NL_DUMP_DETAILS] = flower_dump_details, + }, +}; + +static void __init flower_init(void) +{ + rtnl_tc_register(&flower_ops); +} + +static void __exit flower_exit(void) +{ + rtnl_tc_unregister(&flower_ops); +} diff --git a/lib/route/cls/fw.c b/lib/route/cls/fw.c index b569d4f0..2952efc9 100644 --- a/lib/route/cls/fw.c +++ b/lib/route/cls/fw.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/fw.c fw classifier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com> * Copyright (c) 2006 Siemens AG Oesterreich @@ -94,9 +88,12 @@ static int fw_clone(void *_dst, void *_src) { struct rtnl_fw *dst = _dst, *src = _src; + dst->cf_act = NULL; + dst->cf_police = NULL; + if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act))) return -NLE_NOMEM; - + if (src->cf_police && !(dst->cf_police = nl_data_clone(src->cf_police))) return -NLE_NOMEM; diff --git a/lib/route/cls/mall.c b/lib/route/cls/mall.c index e13ee92f..ded08c6e 100644 --- a/lib/route/cls/mall.c +++ b/lib/route/cls/mall.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/mall.c match-all classifier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2017 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com> */ @@ -108,7 +102,7 @@ int rtnl_mall_append_action(struct rtnl_cls *cls, struct rtnl_act *act) mall->m_mask |= MALL_ATTR_ACTION; err = rtnl_act_append(&mall->m_act, act); - if (err) + if (err < 0) return err; rtnl_act_get(act); @@ -188,7 +182,7 @@ static int mall_msg_parser(struct rtnl_tc *tc, void *data) if (tb[TCA_MATCHALL_ACT]) { mall->m_mask |= MALL_ATTR_ACTION; err = rtnl_act_parse(&mall->m_act, tb[TCA_MATCHALL_ACT]); - if (err) + if (err < 0) return err; } @@ -212,13 +206,13 @@ static int mall_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) int err; err = rtnl_act_fill(msg, TCA_MATCHALL_ACT, mall->m_act); - if (err) + if (err < 0) return err; } return 0; - nla_put_failure: +nla_put_failure: return -NLE_NOMEM; } @@ -228,6 +222,8 @@ static int mall_clone(void *_dst, void *_src) struct rtnl_act *next, *new; int err; + dst->m_act = NULL; + if (src->m_act) { if (!(dst->m_act = rtnl_act_alloc())) return -NLE_NOMEM; diff --git a/lib/route/cls/police.c b/lib/route/cls/police.c index 14b5608d..f7771ae4 100644 --- a/lib/route/cls/police.c +++ b/lib/route/cls/police.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/police.c Policer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> */ diff --git a/lib/route/cls/u32.c b/lib/route/cls/u32.c index f06bc242..56952fb2 100644 --- a/lib/route/cls/u32.c +++ b/lib/route/cls/u32.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * lib/route/cls/u32.c u32 classifier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com> * Copyright (c) 2005-2006 Siemens AG Oesterreich @@ -28,6 +22,8 @@ #include <netlink/route/cls/u32.h> #include <netlink/route/action.h> +#include "netlink-private/utils.h" + /** @cond SKIP */ #define U32_ATTR_DIVISOR 0x001 #define U32_ATTR_HASH 0x002 @@ -121,7 +117,7 @@ static int u32_msg_parser(struct rtnl_tc *tc, void *data) if (tb[TCA_U32_ACT]) { u->cu_mask |= U32_ATTR_ACTION; err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]); - if (err) + if (err < 0) return err; } @@ -183,27 +179,96 @@ static void u32_free_data(struct rtnl_tc *tc, void *data) static int u32_clone(void *_dst, void *_src) { struct rtnl_u32 *dst = _dst, *src = _src; + _nl_auto_nl_data struct nl_data *selector = NULL; + _nl_auto_nl_data struct nl_data *mark = NULL; + _nl_auto_nl_data struct nl_data *police = NULL; + _nl_auto_nl_data struct nl_data *pcnt = NULL; + _nl_auto_nl_data struct nl_data *opts = NULL; + _nl_auto_nl_data struct nl_data *xstats = NULL; + _nl_auto_nl_data struct nl_data *subdata = NULL; + _nl_auto_rtnl_act struct rtnl_act *act = NULL; + + dst->cu_pcnt = NULL; + dst->cu_selector = NULL; + dst->cu_mark = NULL; + dst->cu_act = NULL; + dst->cu_police = NULL; + + if (src->cu_selector) { + if (!(selector = nl_data_clone(src->cu_selector))) + return -NLE_NOMEM; + } - if (src->cu_selector && - !(dst->cu_selector = nl_data_clone(src->cu_selector))) - return -NLE_NOMEM; - - if (src->cu_mark && - !(dst->cu_mark = nl_data_clone(src->cu_mark))) - return -NLE_NOMEM; + if (src->cu_mark) { + if (!(mark = nl_data_clone(src->cu_mark))) + return -NLE_NOMEM; + } if (src->cu_act) { - if (!(dst->cu_act = rtnl_act_alloc())) + if (!(act = rtnl_act_alloc())) return -NLE_NOMEM; - memcpy(dst->cu_act, src->cu_act, sizeof(struct rtnl_act)); + if (src->cu_act->c_opts) { + if (!(opts = nl_data_clone(src->cu_act->c_opts))) + return -NLE_NOMEM; + } + + if (src->cu_act->c_xstats) { + if (!(xstats = nl_data_clone(src->cu_act->c_xstats))) + return -NLE_NOMEM; + } + + if (src->cu_act->c_subdata) { + if (!(subdata = nl_data_clone(src->cu_act->c_subdata))) + return -NLE_NOMEM; + } } - if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police))) - return -NLE_NOMEM; + if (src->cu_police) { + if (!(police = nl_data_clone(src->cu_police))) + return -NLE_NOMEM; + } - if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt))) - return -NLE_NOMEM; + if (src->cu_pcnt) { + if (!(pcnt = nl_data_clone(src->cu_pcnt))) + return -NLE_NOMEM; + } + + /* we've passed the critical point and its safe to proceed */ + + if (selector) + dst->cu_selector = _nl_steal_pointer(&selector); + + if (mark) + dst->cu_mark = _nl_steal_pointer(&mark); + + if (police) + dst->cu_police = _nl_steal_pointer(&police); + + if (pcnt) + dst->cu_pcnt = _nl_steal_pointer(&pcnt); + + if (act) { + dst->cu_act = _nl_steal_pointer(&act); + + /* action nl list next and prev pointers must be updated */ + nl_init_list_head(&dst->cu_act->ce_list); + + if (opts) + dst->cu_act->c_opts = _nl_steal_pointer(&opts); + + if (xstats) + dst->cu_act->c_xstats = _nl_steal_pointer(&xstats); + + if (subdata) + dst->cu_act->c_subdata = _nl_steal_pointer(&subdata); + + if (dst->cu_act->c_link) { + nl_object_get(OBJ_CAST(dst->cu_act->c_link)); + } + + dst->cu_act->a_next = NULL; /* Only clone first in chain */ + } return 0; } @@ -278,7 +343,9 @@ static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, if (p->dp_type == NL_DUMP_STATS && (u->cu_mask & U32_ATTR_PCNT)) { struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data; - nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]); + + nl_dump(p, " successful %llu", + (long long unsigned)pcnt->kcnts[i]); } } } @@ -293,11 +360,6 @@ static void u32_dump_details(struct rtnl_tc *tc, void *data, if (!u) return; - if (!(u->cu_mask & (U32_ATTR_SELECTOR & U32_ATTR_MARK))) { - nl_dump(p, "no-selector no-mark\n"); - return; - } - if (!(u->cu_mask & U32_ATTR_SELECTOR)) { nl_dump(p, "no-selector"); } else { @@ -338,9 +400,11 @@ static void u32_dump_stats(struct rtnl_tc *tc, void *data, if (u->cu_mask & U32_ATTR_PCNT) { struct tc_u32_pcnt *pc = u->cu_pcnt->d_data; + nl_dump(p, "\n"); - nl_dump_line(p, " hit %8" PRIu64 " count %8" PRIu64 "\n", - pc->rhit, pc->rcnt); + nl_dump_line(p, " hit %8llu count %8llu\n", + (long long unsigned)pc->rhit, + (long long unsigned)pc->rcnt); } } @@ -373,7 +437,7 @@ static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) int err; err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act); - if (err) + if (err < 0) return err; } |