summaryrefslogtreecommitdiff
path: root/lib/route/cls
diff options
context:
space:
mode:
Diffstat (limited to 'lib/route/cls')
-rw-r--r--lib/route/cls/.gitignore2
-rw-r--r--lib/route/cls/basic.c10
-rw-r--r--lib/route/cls/cgroup.c23
-rw-r--r--lib/route/cls/ematch.c12
-rw-r--r--lib/route/cls/ematch/cmp.c8
-rw-r--r--lib/route/cls/ematch/container.c8
-rw-r--r--lib/route/cls/ematch/meta.c12
-rw-r--r--lib/route/cls/ematch/nbyte.c8
-rw-r--r--lib/route/cls/ematch/text.c12
-rw-r--r--lib/route/cls/ematch_grammar.l8
-rw-r--r--lib/route/cls/ematch_syntax.y9
-rw-r--r--lib/route/cls/flower.c896
-rw-r--r--lib/route/cls/fw.c13
-rw-r--r--lib/route/cls/mall.c18
-rw-r--r--lib/route/cls/police.c8
-rw-r--r--lib/route/cls/u32.c124
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;
}