summaryrefslogtreecommitdiff
path: root/lib/route
diff options
context:
space:
mode:
Diffstat (limited to 'lib/route')
-rw-r--r--lib/route/.gitignore4
-rw-r--r--lib/route/act.c17
-rw-r--r--lib/route/act/gact.c32
-rw-r--r--lib/route/act/mirred.c31
-rw-r--r--lib/route/act/nat.c288
-rw-r--r--lib/route/act/skbedit.c22
-rw-r--r--lib/route/act/vlan.c18
-rw-r--r--lib/route/addr.c21
-rw-r--r--lib/route/class.c7
-rw-r--r--lib/route/classid.c9
-rw-r--r--lib/route/cls.c79
-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
-rw-r--r--lib/route/link.c343
-rw-r--r--lib/route/link/api.c37
-rw-r--r--lib/route/link/bonding.c11
-rw-r--r--lib/route/link/bridge.c11
-rw-r--r--lib/route/link/can.c149
-rw-r--r--lib/route/link/dummy.c8
-rw-r--r--lib/route/link/geneve.c25
-rw-r--r--lib/route/link/ifb.c8
-rw-r--r--lib/route/link/inet.c8
-rw-r--r--lib/route/link/inet6.c27
-rw-r--r--lib/route/link/ip6gre.c886
-rw-r--r--lib/route/link/ip6tnl.c78
-rw-r--r--lib/route/link/ip6vti.c554
-rw-r--r--lib/route/link/ipgre.c64
-rw-r--r--lib/route/link/ipip.c64
-rw-r--r--lib/route/link/ipvlan.c11
-rw-r--r--lib/route/link/ipvti.c64
-rw-r--r--lib/route/link/macsec.c64
-rw-r--r--lib/route/link/macvlan.c20
-rw-r--r--lib/route/link/ppp.c11
-rw-r--r--lib/route/link/sit.c60
-rw-r--r--lib/route/link/sriov.c24
-rw-r--r--lib/route/link/team.c102
-rw-r--r--lib/route/link/veth.c11
-rw-r--r--lib/route/link/vlan.c12
-rw-r--r--lib/route/link/vrf.c15
-rw-r--r--lib/route/link/vxlan.c38
-rw-r--r--lib/route/link/xfrmi.c8
-rw-r--r--lib/route/mdb.c466
-rw-r--r--lib/route/neigh.c12
-rw-r--r--lib/route/neightbl.c272
-rw-r--r--lib/route/netconf.c18
-rw-r--r--lib/route/nexthop.c15
-rw-r--r--lib/route/nexthop_encap.c7
-rw-r--r--lib/route/nh_encap_mpls.c37
-rw-r--r--lib/route/pktloc.c9
-rw-r--r--lib/route/pktloc_syntax.y1
-rw-r--r--lib/route/qdisc.c39
-rw-r--r--lib/route/qdisc/blackhole.c8
-rw-r--r--lib/route/qdisc/cbq.c8
-rw-r--r--lib/route/qdisc/dsmark.c8
-rw-r--r--lib/route/qdisc/fifo.c8
-rw-r--r--lib/route/qdisc/fq_codel.c8
-rw-r--r--lib/route/qdisc/hfsc.c8
-rw-r--r--lib/route/qdisc/htb.c8
-rw-r--r--lib/route/qdisc/ingress.c8
-rw-r--r--lib/route/qdisc/mqprio.c23
-rw-r--r--lib/route/qdisc/netem.c45
-rw-r--r--lib/route/qdisc/plug.c8
-rw-r--r--lib/route/qdisc/prio.c8
-rw-r--r--lib/route/qdisc/red.c8
-rw-r--r--lib/route/qdisc/sfq.c8
-rw-r--r--lib/route/qdisc/tbf.c14
-rw-r--r--lib/route/route.c34
-rw-r--r--lib/route/route_obj.c193
-rw-r--r--lib/route/route_utils.c7
-rw-r--r--lib/route/rtnl.c7
-rw-r--r--lib/route/rule.c10
-rw-r--r--lib/route/tc.c64
86 files changed, 4546 insertions, 1235 deletions
diff --git a/lib/route/.gitignore b/lib/route/.gitignore
deleted file mode 100644
index debf3b7c..00000000
--- a/lib/route/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-pktloc_grammar.h
-pktloc_grammar.c
-pktloc_syntax.h
-pktloc_syntax.c
diff --git a/lib/route/act.c b/lib/route/act.c
index a0aff7fb..f7c0a78e 100644
--- a/lib/route/act.c
+++ b/lib/route/act.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/act.c Action
- *
- * 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) 2013 Cong Wang <xiyou.wangcong@gmail.com>
*/
@@ -17,6 +10,7 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/utils.h>
#include <netlink-private/tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
@@ -125,7 +119,7 @@ int rtnl_act_fill(struct nl_msg *msg, int attrtype, struct rtnl_act *act)
while (p_act) {
err = rtnl_act_fill_one(msg, p_act, ++order);
- if (err)
+ if (err < 0)
return err;
p_act = p_act->a_next;
}
@@ -519,8 +513,13 @@ static int act_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
p_act = act;
while(p_act) {
err = pp->pp_cb(OBJ_CAST(act), pp);
- if (err)
+ if (err) {
+ if (err > 0) {
+ _nl_assert_not_reached();
+ err = -NLE_FAILURE;
+ }
break;
+ }
p_act = p_act->a_next;
}
errout:
diff --git a/lib/route/act/gact.c b/lib/route/act/gact.c
index e37ef9f5..1a4bacb5 100644
--- a/lib/route/act/gact.c
+++ b/lib/route/act/gact.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/act/gact.c gact action
- *
- * 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) 2016 Sushma Sitaram <sushma.sitaram@intel.com>
*/
@@ -50,14 +44,6 @@ static void gact_free_data(struct rtnl_tc *tc, void *data)
{
}
-static int gact_clone(void *_dst, void *_src)
-{
- struct rtnl_gact *dst = _dst, *src = _src;
-
- memcpy(&dst->g_parm, &src->g_parm, sizeof(src->g_parm));
- return 0;
-}
-
static void gact_dump_line(struct rtnl_tc *tc, void *data,
struct nl_dump_params *p)
{
@@ -126,19 +112,7 @@ int rtnl_gact_set_action(struct rtnl_act *act, int action)
if (!(u = (struct rtnl_gact *) rtnl_tc_data(TC_CAST(act))))
return -NLE_NOMEM;
- if (action > TC_ACT_SHOT || action < TC_ACT_UNSPEC)
- return -NLE_INVAL;
-
- switch (action) {
- case TC_ACT_UNSPEC:
- case TC_ACT_SHOT:
- u->g_parm.action = action;
- break;
- case TC_ACT_OK:
- case TC_ACT_RECLASSIFY:
- default:
- return NLE_OPNOTSUPP;
- }
+ u->g_parm.action = action;
return 0;
}
@@ -161,7 +135,7 @@ static struct rtnl_tc_ops gact_ops = {
.to_size = sizeof(struct rtnl_gact),
.to_msg_parser = gact_msg_parser,
.to_free_data = gact_free_data,
- .to_clone = gact_clone,
+ .to_clone = NULL,
.to_msg_fill = gact_msg_fill,
.to_dump = {
[NL_DUMP_LINE] = gact_dump_line,
diff --git a/lib/route/act/mirred.c b/lib/route/act/mirred.c
index b674fb8c..01da1346 100644
--- a/lib/route/act/mirred.c
+++ b/lib/route/act/mirred.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/act/mirred.c mirred action
- *
- * 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) 2013 Cong Wang <xiyou.wangcong@gmail.com>
*/
@@ -49,14 +43,6 @@ static void mirred_free_data(struct rtnl_tc *tc, void *data)
{
}
-static int mirred_clone(void *_dst, void *_src)
-{
- struct rtnl_mirred *dst = _dst, *src = _src;
-
- memcpy(&dst->m_parm, &src->m_parm, sizeof(src->m_parm));
- return 0;
-}
-
static void mirred_dump_line(struct rtnl_tc *tc, void *data,
struct nl_dump_params *p)
{
@@ -187,19 +173,8 @@ int rtnl_mirred_set_policy(struct rtnl_act *act, int policy)
if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act))))
return -NLE_NOMEM;
- if (policy > TC_ACT_REPEAT || policy < TC_ACT_OK)
- return -NLE_INVAL;
+ u->m_parm.action = policy;
- switch (u->m_parm.eaction) {
- case TCA_EGRESS_MIRROR:
- case TCA_EGRESS_REDIR:
- u->m_parm.action = policy;
- break;
- case TCA_INGRESS_REDIR:
- case TCA_INGRESS_MIRROR:
- default:
- return NLE_OPNOTSUPP;
- }
return 0;
}
@@ -220,7 +195,7 @@ static struct rtnl_tc_ops mirred_ops = {
.to_size = sizeof(struct rtnl_mirred),
.to_msg_parser = mirred_msg_parser,
.to_free_data = mirred_free_data,
- .to_clone = mirred_clone,
+ .to_clone = NULL,
.to_msg_fill = mirred_msg_fill,
.to_dump = {
[NL_DUMP_LINE] = mirred_dump_line,
diff --git a/lib/route/act/nat.c b/lib/route/act/nat.c
new file mode 100644
index 00000000..21c42476
--- /dev/null
+++ b/lib/route/act/nat.c
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Copyright (c) 2016 Magnus Öberg <magnus.oberg@westermo.se>
+ */
+
+/**
+ * @ingroup act
+ * @defgroup act_nat NAT
+ *
+ * @{
+ */
+
+#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/act/nat.h>
+#include <netlink/route/tc.h>
+
+static struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
+ [TCA_NAT_PARMS] = { .minlen = sizeof(struct tc_nat) },
+};
+
+/**
+ * nat operations
+ */
+
+static int nat_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct tc_nat *nat = data;
+ struct nlattr *tb[TCA_NAT_MAX + 1];
+ int err;
+
+ err = tca_parse(tb, TCA_NAT_MAX, tc, nat_policy);
+ if (err < 0)
+ return err;
+
+ if (!tb[TCA_NAT_PARMS])
+ return -NLE_MISSING_ATTR;
+
+ nla_memcpy(nat, tb[TCA_NAT_PARMS], sizeof(*nat));
+
+ return NLE_SUCCESS;
+}
+
+static void nat_free_data(struct rtnl_tc *tc, void *data)
+{
+}
+
+static int nat_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct tc_nat *nat = data;
+
+ if (!nat)
+ return -NLE_OBJ_NOTFOUND;
+
+ NLA_PUT(msg, TCA_NAT_PARMS, sizeof(*nat), nat);
+
+ return NLE_SUCCESS;
+
+nla_put_failure:
+ return -NLE_NOMEM;
+}
+
+static void nat_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct tc_nat *nat = data;
+ char buf[32];
+ uint32_t mask;
+ int pfx = 0;
+
+ if (!nat)
+ return;
+
+ if (nat->flags & TCA_NAT_FLAG_EGRESS)
+ nl_dump(p, " egress");
+ else
+ nl_dump(p, " ingress");
+
+ mask = nat->mask;
+ while (mask > 0) {
+ mask = mask >> 1;
+ pfx++;
+ }
+
+ inet_ntop(AF_INET, &nat->old_addr, buf, sizeof(buf));
+ nl_dump(p, " %s", buf);
+ if (pfx < 32)
+ nl_dump(p, "/%d", pfx);
+
+ inet_ntop(AF_INET, &nat->new_addr, buf, sizeof(buf));
+ nl_dump(p, " %s", buf);
+ if (pfx < 32)
+ nl_dump(p, "/%d", pfx);
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+/**
+ * Set old IPv4 address on a netlink NAT action object
+ * @arg act Action object
+ * @arg addr Binary IPv4 address in host byte order
+ *
+ * @return 0 on success or negative error code in case of an error.
+ */
+int rtnl_nat_set_old_addr(struct rtnl_act *act, in_addr_t addr)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ nat->old_addr = addr;
+
+ return NLE_SUCCESS;
+}
+
+int rtnl_nat_get_old_addr(struct rtnl_act *act, in_addr_t *addr)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOATTR;
+
+ *addr = nat->old_addr;
+
+ return NLE_SUCCESS;
+}
+
+/**
+ * Set new IPv4 address on a netlink NAT action object
+ * @arg act Action object
+ * @arg addr Binary IPv4 address in host byte order
+ *
+ * @return 0 on success or negative error code in case of an error.
+ */
+int rtnl_nat_set_new_addr(struct rtnl_act *act, in_addr_t addr)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ nat->new_addr = addr;
+
+ return NLE_SUCCESS;
+}
+
+int rtnl_nat_get_new_addr(struct rtnl_act *act, in_addr_t *addr)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOATTR;
+
+ *addr = nat->new_addr;
+
+ return NLE_SUCCESS;
+}
+
+/**
+ * Set IPv4 address mask on a netlink NAT action object
+ * @arg act Action object
+ * @arg mask IPv4 address mask
+ *
+ * @return 0 on success or negative error code in case of an error.
+ */
+int rtnl_nat_set_mask(struct rtnl_act *act, in_addr_t bitmask)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ nat->mask = bitmask;
+
+ return NLE_SUCCESS;
+}
+
+int rtnl_nat_get_mask(struct rtnl_act *act, in_addr_t *bitmask)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOATTR;
+
+ *bitmask = nat->mask;
+
+ return NLE_SUCCESS;
+}
+
+/**
+ * Set flags for a netlink NAT action object
+ * @arg act Action object
+ * @arg flags TCA_NAT_FLAG_* flags.
+ *
+ * Currently only TCA_NAT_FLAG_EGRESS is defined. Selects NAT on
+ * egress/IP src if set, ingress/IP dst otherwise.
+ *
+ * @return 0 on success or negative error code in case of an error.
+ */
+int rtnl_nat_set_flags(struct rtnl_act *act, uint32_t flags)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ nat->flags = flags;
+
+ return NLE_SUCCESS;
+}
+
+int rtnl_nat_get_flags(struct rtnl_act *act, uint32_t *flags)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOATTR;
+
+ *flags = nat->flags;
+
+ return NLE_SUCCESS;
+}
+
+int rtnl_nat_set_action(struct rtnl_act *act, int action)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (action < TC_ACT_UNSPEC)
+ return -NLE_INVAL;
+
+ nat->action = action;
+
+ return NLE_SUCCESS;
+}
+
+int rtnl_nat_get_action(struct rtnl_act *act, int *action)
+{
+ struct tc_nat *nat;
+
+ if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOATTR;
+
+ *action = nat->action;
+
+ return NLE_SUCCESS;
+}
+
+/**
+ * @}
+ */
+
+static struct rtnl_tc_ops nat_ops = {
+ .to_kind = "nat",
+ .to_type = RTNL_TC_TYPE_ACT,
+ .to_size = sizeof(struct tc_nat),
+ .to_msg_parser = nat_msg_parser,
+ .to_free_data = nat_free_data,
+ .to_clone = NULL,
+ .to_msg_fill = nat_msg_fill,
+ .to_dump = {
+ [NL_DUMP_LINE] = nat_dump_line,
+ },
+};
+
+static void __init nat_init(void)
+{
+ rtnl_tc_register(&nat_ops);
+}
+
+static void __exit nat_exit(void)
+{
+ rtnl_tc_unregister(&nat_ops);
+}
+
+/**
+ * @}
+ */
diff --git a/lib/route/act/skbedit.c b/lib/route/act/skbedit.c
index d85265ee..24f57e56 100644
--- a/lib/route/act/skbedit.c
+++ b/lib/route/act/skbedit.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/act/skbedit.c skbedit action
- *
- * 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) 2015 Cong Wang <xiyou.wangcong@gmail.com>
*/
@@ -67,14 +61,6 @@ static void skbedit_free_data(struct rtnl_tc *tc, void *data)
{
}
-static int skbedit_clone(void *_dst, void *_src)
-{
- struct rtnl_skbedit *dst = _dst, *src = _src;
-
- memcpy(dst, src, sizeof(*src));
- return 0;
-}
-
static void skbedit_dump_line(struct rtnl_tc *tc, void *data,
struct nl_dump_params *p)
{
@@ -166,10 +152,8 @@ int rtnl_skbedit_set_action(struct rtnl_act *act, int action)
if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
return -NLE_NOMEM;
- if (action > TC_ACT_REPEAT || action < TC_ACT_UNSPEC)
- return -NLE_INVAL;
-
u->s_parm.action = action;
+
return 0;
}
@@ -268,7 +252,7 @@ static struct rtnl_tc_ops skbedit_ops = {
.to_size = sizeof(struct rtnl_skbedit),
.to_msg_parser = skbedit_msg_parser,
.to_free_data = skbedit_free_data,
- .to_clone = skbedit_clone,
+ .to_clone = NULL,
.to_msg_fill = skbedit_msg_fill,
.to_dump = {
[NL_DUMP_LINE] = skbedit_dump_line,
diff --git a/lib/route/act/vlan.c b/lib/route/act/vlan.c
index 69b6f240..3d9fc334 100644
--- a/lib/route/act/vlan.c
+++ b/lib/route/act/vlan.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/act/vlan.c vlan action
- *
- * 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) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
*/
@@ -109,14 +103,6 @@ static void vlan_free_data(struct rtnl_tc *tc, void *data)
{
}
-static int vlan_clone(void *_dst, void *_src)
-{
- struct rtnl_vlan *dst = _dst, *src = _src;
-
- memcpy(&dst->v_parm, &src->v_parm, sizeof(src->v_parm));
- return 0;
-}
-
static void vlan_dump_line(struct rtnl_tc *tc, void *data,
struct nl_dump_params *p)
{
@@ -405,7 +391,7 @@ static struct rtnl_tc_ops vlan_ops = {
.to_size = sizeof(struct rtnl_vlan),
.to_msg_parser = vlan_msg_parser,
.to_free_data = vlan_free_data,
- .to_clone = vlan_clone,
+ .to_clone = NULL,
.to_msg_fill = vlan_msg_fill,
.to_dump = {
[NL_DUMP_LINE] = vlan_dump_line,
diff --git a/lib/route/addr.c b/lib/route/addr.c
index f65e7e9b..28734499 100644
--- a/lib/route/addr.c
+++ b/lib/route/addr.c
@@ -1,15 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/addr.c Addresses
- *
- * 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-2012 Thomas Graf <tgraf@suug.ch>
- * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>,
- * Mediatrix Telecom, inc. <ericb@mediatrix.com>
+ * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>
+ * Copyright (c) 2003-2006 Mediatrix Telecom, inc. <ericb@mediatrix.com>
*/
/**
@@ -160,6 +153,13 @@ static int addr_clone(struct nl_object *_dst, struct nl_object *_src)
struct rtnl_addr *dst = nl_object_priv(_dst);
struct rtnl_addr *src = nl_object_priv(_src);
+ dst->a_peer = NULL;
+ dst->a_local = NULL;
+ dst->a_bcast = NULL;
+ dst->a_anycast = NULL;
+ dst->a_multicast = NULL;
+ dst->a_link = NULL;
+
if (src->a_link) {
nl_object_get(OBJ_CAST(src->a_link));
dst->a_link = src->a_link;
@@ -168,7 +168,7 @@ static int addr_clone(struct nl_object *_dst, struct nl_object *_src)
if (src->a_peer)
if (!(dst->a_peer = nl_addr_clone(src->a_peer)))
return -NLE_NOMEM;
-
+
if (src->a_local)
if (!(dst->a_local = nl_addr_clone(src->a_local)))
return -NLE_NOMEM;
@@ -1136,6 +1136,7 @@ static const struct trans_tbl addr_flags[] = {
__ADD(IFA_F_SECONDARY, secondary),
__ADD(IFA_F_NODAD, nodad),
__ADD(IFA_F_OPTIMISTIC, optimistic),
+ __ADD(IFA_F_DADFAILED, dadfailed),
__ADD(IFA_F_HOMEADDRESS, homeaddress),
__ADD(IFA_F_DEPRECATED, deprecated),
__ADD(IFA_F_TENTATIVE, tentative),
diff --git a/lib/route/class.c b/lib/route/class.c
index d1641126..76cfac99 100644
--- a/lib/route/class.c
+++ b/lib/route/class.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/class.c Traffic Classes
- *
- * 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/classid.c b/lib/route/classid.c
index 9dcf993d..350962ac 100644
--- a/lib/route/classid.c
+++ b/lib/route/classid.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/classid.c ClassID Management
- *
- * 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>
*/
@@ -415,7 +408,7 @@ int rtnl_classid_generate(const char *name, uint32_t *result, uint32_t parent)
fclose(fd);
- if ((err = classid_map_add(classid, name)) < 0) {
+ if (classid_map_add(classid, name) < 0) {
/*
* Error adding classid map, re-read classid file is best
* option here. It is likely to fail as well but better
diff --git a/lib/route/cls.c b/lib/route/cls.c
index fa87cd40..8583103b 100644
--- a/lib/route/cls.c
+++ b/lib/route/cls.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/classifier.c 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>
*/
@@ -364,6 +357,78 @@ void rtnl_cls_cache_set_tc_params(struct nl_cache *cache,
cache->c_iarg2 = parent;
}
+/**
+ * Search classifier by interface index, parent and handle
+ * @arg cache Classifier cache
+ * @arg ifindex Interface index
+ * @arg parent Parent
+ * @arg handle Handle
+ *
+ * Searches a classifier cache previously allocated with rtnl_cls_alloc_cache()
+ * and searches for a classifier matching the interface index, parent
+ * and handle.
+ *
+ * The reference counter is incremented before returning the classifier,
+ * therefore the reference must be given back with rtnl_cls_put() after usage.
+ *
+ * @return Classifier or NULL if no match was found.
+ */
+struct rtnl_cls *rtnl_cls_find_by_handle(struct nl_cache *cache, int ifindex, uint32_t parent,
+ uint32_t handle)
+{
+ struct rtnl_cls *cls;
+
+ if (cache->c_ops != &rtnl_cls_ops)
+ return NULL;
+
+ nl_list_for_each_entry(cls, &cache->c_items, ce_list) {
+ if ((cls->c_parent == parent) &&
+ (cls->c_ifindex == ifindex)&&
+ (cls->c_handle == handle)) {
+ nl_object_get((struct nl_object *) cls);
+ return cls;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Search classifier by interface index, parent and priority
+ * @arg cache Classifier cache
+ * @arg ifindex Interface index
+ * @arg parent Parent
+ * @arg prio Priority
+ *
+ * Searches a classifier cache previously allocated with rtnl_cls_alloc_cache()
+ * and searches for a classifier matching the interface index, parent
+ * and prio.
+ *
+ * The reference counter is incremented before returning the classifier,
+ * therefore the reference must be given back with rtnl_cls_put() after usage.
+ *
+ * @return Classifier or NULL if no match was found.
+ */
+struct rtnl_cls *rtnl_cls_find_by_prio(struct nl_cache *cache, int ifindex,
+ uint32_t parent, uint16_t prio)
+{
+ struct rtnl_cls *cls;
+
+ if (cache->c_ops != &rtnl_cls_ops)
+ return NULL;
+
+ nl_list_for_each_entry(cls, &cache->c_items, ce_list) {
+ if ((cls->c_parent == parent) &&
+ (cls->c_ifindex == ifindex) &&
+ (cls->c_prio == prio)) {
+ nl_object_get((struct nl_object *) cls);
+ return cls;
+ }
+ }
+
+ return NULL;
+}
+
/** @} */
static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
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;
}
diff --git a/lib/route/link.c b/lib/route/link.c
index df01a71a..df8ea5bb 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link.c Links (Interfaces)
- *
- * 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-2012 Thomas Graf <tgraf@suug.ch>
*/
@@ -93,13 +86,12 @@ static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
int family)
{
struct rtnl_link_af_ops *af_ops;
- void *data;
af_ops = rtnl_link_af_ops_lookup(family);
if (!af_ops)
return NULL;
- if (!(data = rtnl_link_af_alloc(link, af_ops))) {
+ if (!rtnl_link_af_alloc(link, af_ops)) {
rtnl_link_af_ops_put(af_ops);
return NULL;
}
@@ -223,22 +215,19 @@ static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
static int do_foreach_af(struct rtnl_link *link,
int (*cb)(struct rtnl_link *,
- struct rtnl_link_af_ops *, void *, void *),
+ struct rtnl_link_af_ops *, void *, void *),
void *arg)
{
int i, err;
for (i = 0; i < AF_MAX; i++) {
if (link->l_af_data[i]) {
- struct rtnl_link_af_ops *ops;
+ _nl_auto_rtnl_link_af_ops struct rtnl_link_af_ops *ops = NULL;
if (!(ops = rtnl_link_af_ops_lookup(i)))
BUG();
err = cb(link, ops, link->l_af_data[i], arg);
-
- rtnl_link_af_ops_put(ops);
-
if (err < 0)
return err;
}
@@ -296,6 +285,19 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src)
struct rtnl_link *src = nl_object_priv(_src);
int err;
+ dst->l_addr = NULL;
+ dst->l_bcast = NULL;
+ dst->l_info_kind = NULL;
+ dst->l_info_slave_kind = NULL;
+ dst->l_info_ops = NULL;
+ memset(dst->l_af_data, 0, sizeof (dst->l_af_data));
+ dst->l_info = NULL;
+ dst->l_ifalias = NULL;
+ dst->l_af_ops = NULL;
+ dst->l_phys_port_id = NULL;
+ dst->l_phys_switch_id = NULL;
+ dst->l_vf_list = NULL;
+
if (src->l_addr)
if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
return -NLE_NOMEM;
@@ -316,15 +318,24 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src)
if (!(dst->l_info_slave_kind = strdup(src->l_info_slave_kind)))
return -NLE_NOMEM;
- if (src->l_info_ops && src->l_info_ops->io_clone) {
- err = src->l_info_ops->io_clone(dst, src);
- if (err < 0)
- return err;
+ if (src->l_info_ops) {
+
+ rtnl_link_info_ops_get(src->l_info_ops);
+ dst->l_info_ops = src->l_info_ops;
+
+ if (src->l_info_ops->io_clone) {
+ err = src->l_info_ops->io_clone(dst, src);
+ if (err < 0)
+ return err;
+ }
}
if ((err = do_foreach_af(src, af_clone, dst)) < 0)
return err;
+ if (src->l_af_ops)
+ dst->l_af_ops = af_lookup_and_alloc(dst, src->l_af_ops->ao_family);
+
if (src->l_phys_port_id)
if (!(dst->l_phys_port_id = nl_data_clone(src->l_phys_port_id)))
return -NLE_NOMEM;
@@ -387,7 +398,7 @@ int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
return -NLE_MISSING_ATTR;
nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
-
+ link->ce_mask |= LINK_ATTR_IFNAME;
if (tb[IFLA_STATS]) {
struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
@@ -580,28 +591,22 @@ int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *n, struct nl_parser_param *pp)
{
- struct rtnl_link *link;
+ _nl_auto_rtnl_link struct rtnl_link *link = NULL;
+ struct nla_policy real_link_policy[ARRAY_SIZE(rtln_link_policy)];
+ struct nla_policy *link_policy = rtln_link_policy;
+ struct rtnl_link_af_ops *af_ops_family;
struct ifinfomsg *ifi;
struct nlattr *tb[IFLA_MAX+1];
- struct rtnl_link_af_ops *af_ops = NULL;
- struct rtnl_link_af_ops *af_ops_family;
int err, family;
- struct nla_policy real_link_policy[IFLA_MAX+1];
-
- memcpy(&real_link_policy, rtln_link_policy, sizeof(rtln_link_policy));
link = rtnl_link_alloc();
- if (link == NULL) {
- err = -NLE_NOMEM;
- goto errout;
- }
+ if (link == NULL)
+ return -NLE_NOMEM;
link->ce_msgtype = n->nlmsg_type;
- if (!nlmsg_valid_hdr(n, sizeof(*ifi))) {
- err = -NLE_MSG_TOOSHORT;
- goto errout;
- }
+ if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
+ return -NLE_MSG_TOOSHORT;
ifi = nlmsg_data(n);
link->l_family = family = ifi->ifi_family;
@@ -609,35 +614,37 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
link->l_index = ifi->ifi_index;
link->l_flags = ifi->ifi_flags;
link->l_change = ifi->ifi_change;
- link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
+ link->ce_mask = (LINK_ATTR_FAMILY |
LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
- if ((af_ops_family = af_ops = af_lookup_and_alloc(link, family))) {
- if (af_ops->ao_protinfo_policy) {
+ if ((link->l_af_ops = af_lookup_and_alloc(link, family))) {
+ if (link->l_af_ops->ao_protinfo_policy) {
+ _NL_STATIC_ASSERT (sizeof(rtln_link_policy) == sizeof(real_link_policy));
+ memcpy(&real_link_policy, rtln_link_policy, sizeof(rtln_link_policy));
memcpy(&real_link_policy[IFLA_PROTINFO],
- af_ops->ao_protinfo_policy,
+ link->l_af_ops->ao_protinfo_policy,
sizeof(struct nla_policy));
+ link_policy = real_link_policy;
}
-
- link->l_af_ops = af_ops;
}
- err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, real_link_policy);
+ af_ops_family = link->l_af_ops;
+
+ err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
if (err < 0)
- goto errout;
+ return err;
err = rtnl_link_info_parse(link, tb);
if (err < 0)
- goto errout;
+ return err;
if (tb[IFLA_NUM_VF]) {
link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
link->ce_mask |= LINK_ATTR_NUM_VF;
if (link->l_num_vf && tb[IFLA_VFINFO_LIST]) {
- if ((err = rtnl_link_sriov_parse_vflist(link, tb)) < 0) {
- goto errout;
- }
+ if ((err = rtnl_link_sriov_parse_vflist(link, tb)) < 0)
+ return err;
link->ce_mask |= LINK_ATTR_VF_LIST;
}
}
@@ -648,7 +655,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
link_info_policy);
if (err < 0)
- goto errout;
+ return err;
if (li[IFLA_INFO_KIND]) {
struct rtnl_link_info_ops *ops;
@@ -657,18 +664,19 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
err = rtnl_link_set_type(link, kind);
if (err < 0)
- goto errout;
-
- if ((af = nl_str2af(kind)) >= 0 &&
- !af_ops && (af_ops = af_lookup_and_alloc(link, af))) {
+ return err;
- if (af_ops->ao_protinfo_policy) {
- tb[IFLA_PROTINFO] = (struct nlattr *)af_ops->ao_protinfo_policy;
- }
+ if ( (af = nl_str2af(kind)) >= 0
+ && !link->l_af_ops
+ && (link->l_af_ops = af_lookup_and_alloc(link, af))) {
link->l_family = af;
- link->l_af_ops = af_ops;
+ if (link->l_af_ops->ao_protinfo_policy)
+ tb[IFLA_PROTINFO] = (struct nlattr *)link->l_af_ops->ao_protinfo_policy;
}
+ if (link->l_info_ops)
+ release_link_info(link);
+
ops = rtnl_link_info_ops_lookup(kind);
link->l_info_ops = ops;
@@ -678,7 +686,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
err = ops->io_parse(link, li[IFLA_INFO_DATA],
li[IFLA_INFO_XSTATS]);
if (err < 0)
- goto errout;
+ return err;
} else {
/* XXX: Warn about unparsed info? */
}
@@ -692,17 +700,19 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
err = rtnl_link_set_slave_type(link, kind);
if (err < 0)
- goto errout;
+ return err;
link->ce_mask |= LINK_ATTR_LINKINFO_SLAVE_KIND;
}
}
- if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
- err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
- link->l_af_data[link->l_family]);
+ if ( tb[IFLA_PROTINFO]
+ && link->l_af_ops
+ && link->l_af_ops->ao_parse_protinfo) {
+ err = link->l_af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
+ link->l_af_data[link->l_family]);
if (err < 0)
- goto errout;
+ return err;
link->ce_mask |= LINK_ATTR_PROTINFO;
}
@@ -710,25 +720,28 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
/* parsing of IFLA_AF_SPEC is dependent on the family used
* in the request message.
*/
- if (af_ops_family && af_ops_family->ao_parse_af_full) {
+ if ( af_ops_family
+ && af_ops_family->ao_parse_af_full) {
err = af_ops_family->ao_parse_af_full(link,
tb[IFLA_AF_SPEC],
link->l_af_data[af_ops_family->ao_family]);
if (err < 0)
- goto errout;
+ return err;
link->ce_mask |= LINK_ATTR_AF_SPEC;
} else if (family == AF_UNSPEC) {
struct nlattr *af_attr;
int remaining;
nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
+ _nl_auto_rtnl_link_af_ops struct rtnl_link_af_ops *af_ops = NULL;
+
af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
if (af_ops && af_ops->ao_parse_af) {
char *af_data = link->l_af_data[nla_type(af_attr)];
err = af_ops->ao_parse_af(link, af_attr, af_data);
if (err < 0)
- goto errout;
+ return err;
}
}
link->ce_mask |= LINK_ATTR_AF_SPEC;
@@ -770,10 +783,8 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
if (tb[IFLA_PHYS_PORT_ID]) {
link->l_phys_port_id = nl_data_alloc_attr(tb[IFLA_PHYS_PORT_ID]);
- if (link->l_phys_port_id == NULL) {
- err = -NLE_NOMEM;
- goto errout;
- }
+ if (link->l_phys_port_id == NULL)
+ return -NLE_NOMEM;
link->ce_mask |= LINK_ATTR_PHYS_PORT_ID;
}
@@ -784,26 +795,20 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
if (tb[IFLA_PHYS_SWITCH_ID]) {
link->l_phys_switch_id = nl_data_alloc_attr(tb[IFLA_PHYS_SWITCH_ID]);
- if (link->l_phys_switch_id == NULL) {
- err = -NLE_NOMEM;
- goto errout;
- }
+ if (link->l_phys_switch_id == NULL)
+ return -NLE_NOMEM;
link->ce_mask |= LINK_ATTR_PHYS_SWITCH_ID;
}
- err = pp->pp_cb((struct nl_object *) link, pp);
-errout:
- rtnl_link_af_ops_put(af_ops);
- rtnl_link_put(link);
- return err;
+ return pp->pp_cb((struct nl_object *) link, pp);
}
static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
{
+ _nl_auto_nl_msg struct nl_msg *msg = NULL;
int family = cache->c_iarg1;
struct ifinfomsg hdr = { .ifi_family = family };
struct rtnl_link_af_ops *ops;
- struct nl_msg *msg;
int err;
__u32 ext_filter_mask = RTEXT_FILTER_VF;
@@ -811,30 +816,27 @@ static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
if (!msg)
return -NLE_NOMEM;
- err = -NLE_MSGSIZE;
if (nlmsg_append(msg, &hdr, sizeof(hdr), NLMSG_ALIGNTO) < 0)
- goto nla_put_failure;
+ return -NLE_MSGSIZE;
ops = rtnl_link_af_ops_lookup(family);
if (ops && ops->ao_get_af) {
err = ops->ao_get_af(msg, &ext_filter_mask);
- if (err)
- goto nla_put_failure;
+ if (err < 0)
+ return err;
}
if (ext_filter_mask) {
err = nla_put(msg, IFLA_EXT_MASK, sizeof(ext_filter_mask), &ext_filter_mask);
- if (err)
- goto nla_put_failure;
+ if (err < 0)
+ return err;
}
err = nl_send_auto(sk, msg);
- if (err > 0)
- err = 0;
+ if (err < 0)
+ return 0;
-nla_put_failure:
- nlmsg_free(msg);
- return err;
+ return 0;
}
static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
@@ -860,10 +862,9 @@ static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
if (link->ce_mask & LINK_ATTR_MASTER) {
if (cache) {
- struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
+ _nl_auto_rtnl_link struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
+
nl_dump(p, "master %s ", master ? master->l_name : "inv");
- if (master)
- rtnl_link_put(master);
} else
nl_dump(p, "master %d ", link->l_master);
}
@@ -875,10 +876,9 @@ static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
if (link->ce_mask & LINK_ATTR_LINK) {
if ( cache
&& !(link->ce_mask & LINK_ATTR_LINK_NETNSID)) {
- struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
+ _nl_auto_rtnl_link struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
+
nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
- if (ll)
- rtnl_link_put(ll);
} else
nl_dump(p, "slave-of %d ", link->l_link);
}
@@ -1369,10 +1369,9 @@ struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
int rtnl_link_build_get_request(int ifindex, const char *name,
struct nl_msg **result)
{
+ _nl_auto_nl_msg struct nl_msg *msg = NULL;
struct ifinfomsg ifi;
- struct nl_msg *msg;
__u32 vf_mask = RTEXT_FILTER_VF;
- int err = -NLE_MSGSIZE;
if (ifindex <= 0 && !name) {
APPBUG("ifindex or name must be specified");
@@ -1387,24 +1386,15 @@ int rtnl_link_build_get_request(int ifindex, const char *name,
if (ifindex > 0)
ifi.ifi_index = ifindex;
- if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) {
- err = -NLE_MSGSIZE;
- goto nla_put_failure;
- }
+ _NL_RETURN_ON_PUT_ERR(nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO));
if (name)
- NLA_PUT_STRING(msg, IFLA_IFNAME, name);
+ _NL_RETURN_ON_PUT_ERR(nla_put_string(msg, IFLA_IFNAME, name));
- err = nla_put(msg, IFLA_EXT_MASK, sizeof(vf_mask), &vf_mask);
- if (err)
- goto nla_put_failure;
+ _NL_RETURN_ON_PUT_ERR(nla_put(msg, IFLA_EXT_MASK, sizeof(vf_mask), &vf_mask));
- *result = msg;
+ *result = _nl_steal_pointer(&msg);
return 0;
-
-nla_put_failure:
- nlmsg_free(msg);
- return err;
}
/**
@@ -1431,8 +1421,8 @@ nla_put_failure:
int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
struct rtnl_link **result)
{
- struct nl_msg *msg = NULL;
- struct nl_object *obj;
+ _nl_auto_rtnl_link struct rtnl_link *link = NULL;
+ _nl_auto_nl_msg struct nl_msg *msg = NULL;
int err;
int syserr;
@@ -1440,14 +1430,15 @@ int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
return err;
err = nl_send_auto(sk, msg);
- nlmsg_free(msg);
if (err < 0)
return err;
- if ((err = nl_pickup_keep_syserr(sk, link_msg_parser, &obj, &syserr)) < 0) {
- if (syserr == -EINVAL &&
- ifindex <= 0 &&
- name && *name) {
+ err = nl_pickup_keep_syserr(sk, link_msg_parser, (struct nl_object **) &link, &syserr);
+ if (err < 0) {
+ if ( syserr == -EINVAL
+ && ifindex <= 0
+ && name
+ && *name) {
/* Older kernels do not support lookup by ifname. This was added
* by commit kernel a3d1289126e7b14307074b76bf1677015ea5036f .
* Detect this error case and return NLE_OPNOTSUPP instead of
@@ -1457,13 +1448,11 @@ int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
return err;
}
- /* We have used link_msg_parser(), object is definitely a link */
- *result = (struct rtnl_link *) obj;
-
/* If an object has been returned, we also need to wait for the ACK */
- if (err == 0 && obj)
+ if (err == 0 && link)
wait_for_ack(sk);
+ *result = _nl_steal_pointer(&link);
return 0;
}
@@ -1484,11 +1473,11 @@ int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
size_t len)
{
- struct rtnl_link *link = rtnl_link_get(cache, ifindex);
+ _nl_auto_rtnl_link struct rtnl_link *link = NULL;
+ link = rtnl_link_get(cache, ifindex);
if (link) {
- strncpy(dst, link->l_name, len - 1);
- rtnl_link_put(link);
+ _nl_strncpy_trunc(dst, link->l_name, len);
return dst;
}
@@ -1506,16 +1495,13 @@ char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
*/
int rtnl_link_name2i(struct nl_cache *cache, const char *name)
{
- int ifindex = 0;
- struct rtnl_link *link;
+ _nl_auto_rtnl_link struct rtnl_link *link = NULL;
link = rtnl_link_get_by_name(cache, name);
- if (link) {
- ifindex = link->l_index;
- rtnl_link_put(link);
- }
+ if (link)
+ return link->l_index;
- return ifindex;
+ return 0;
}
/** @} */
@@ -1582,7 +1568,7 @@ nla_put_failure:
static int build_link_msg(int cmd, struct ifinfomsg *hdr,
struct rtnl_link *link, int flags, struct nl_msg **result)
{
- struct nl_msg *msg;
+ _nl_auto_nl_msg struct nl_msg *msg = NULL;
struct nlattr *af_spec;
msg = nlmsg_alloc_simple(cmd, flags);
@@ -1637,11 +1623,10 @@ static int build_link_msg(int cmd, struct ifinfomsg *hdr,
nla_nest_end(msg, af_spec);
- *result = msg;
+ *result = _nl_steal_pointer(&msg);
return 0;
nla_put_failure:
- nlmsg_free(msg);
return -NLE_MSGSIZE;
}
@@ -1759,12 +1744,9 @@ int rtnl_link_build_change_request(struct rtnl_link *orig,
rt = af_request_type(orig->l_family, changes);
if ((err = build_link_msg(rt, &ifi, changes, flags, result)) < 0)
- goto errout;
+ return err;
return 0;
-
-errout:
- return err;
}
/**
@@ -1805,7 +1787,7 @@ errout:
int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
struct rtnl_link *changes, int flags)
{
- struct nl_msg *msg;
+ _nl_auto_nl_msg struct nl_msg *msg = NULL;
int err;
err = rtnl_link_build_change_request(orig, changes, flags, &msg);
@@ -1816,18 +1798,20 @@ int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
retry:
err = nl_send_auto_complete(sk, msg);
if (err < 0)
- goto errout;
+ return err;
err = wait_for_ack(sk);
- if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
+ if ( err == -NLE_OPNOTSUPP
+ && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
msg->nm_nlh->nlmsg_type = RTM_SETLINK;
msg->nm_nlh->nlmsg_seq = NL_AUTO_SEQ;
goto retry;
}
-errout:
- nlmsg_free(msg);
- return err;
+ if (err < 0)
+ return err;
+
+ return 0;
}
/** @} */
@@ -1853,7 +1837,7 @@ errout:
int rtnl_link_build_delete_request(const struct rtnl_link *link,
struct nl_msg **result)
{
- struct nl_msg *msg;
+ _nl_auto_nl_msg struct nl_msg *msg = NULL;
struct ifinfomsg ifi = {
.ifi_index = link->l_index,
};
@@ -1866,18 +1850,13 @@ int rtnl_link_build_delete_request(const struct rtnl_link *link,
if (!(msg = nlmsg_alloc_simple(RTM_DELLINK, 0)))
return -NLE_NOMEM;
- if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
- goto nla_put_failure;
+ _NL_RETURN_ON_PUT_ERR(nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO));
if (link->ce_mask & LINK_ATTR_IFNAME)
- NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
+ _NL_RETURN_ON_PUT_ERR(nla_put_string(msg, IFLA_IFNAME, link->l_name));
- *result = msg;
+ *result = _nl_steal_pointer(&msg);
return 0;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -NLE_MSGSIZE;
}
/**
@@ -1958,7 +1937,7 @@ void rtnl_link_put(struct rtnl_link *link)
*/
void rtnl_link_set_name(struct rtnl_link *link, const char *name)
{
- strncpy(link->l_name, name, sizeof(link->l_name) - 1);
+ _nl_strncpy_trunc(link->l_name, name, sizeof(link->l_name));
link->ce_mask |= LINK_ATTR_IFNAME;
}
@@ -2125,9 +2104,10 @@ void rtnl_link_set_family(struct rtnl_link *link, int family)
link->ce_mask |= LINK_ATTR_FAMILY;
if (link->l_af_ops) {
- af_free(link, link->l_af_ops,
- link->l_af_data[link->l_af_ops->ao_family], NULL);
- link->l_af_data[link->l_af_ops->ao_family] = NULL;
+ int ao_family = link->l_af_ops->ao_family;
+
+ af_free(link, link->l_af_ops, link->l_af_data[ao_family], NULL);
+ link->l_af_data[ao_family] = NULL;
}
link->l_af_ops = af_lookup_and_alloc(link, family);
@@ -2482,7 +2462,7 @@ void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias)
*/
void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name)
{
- strncpy(link->l_qdisc, name, sizeof(link->l_qdisc) - 1);
+ _nl_strncpy_trunc(link->l_qdisc, name, sizeof(link->l_qdisc));
link->ce_mask |= LINK_ATTR_QDISC;
}
@@ -2568,8 +2548,8 @@ int rtnl_link_set_stat(struct rtnl_link *link, rtnl_link_stat_id_t id,
int rtnl_link_set_type(struct rtnl_link *link, const char *type)
{
struct rtnl_link_info_ops *io;
+ _nl_auto_free char *kind = NULL;
int err;
- char *kind;
free(link->l_info_kind);
link->ce_mask &= ~LINK_ATTR_LINKINFO;
@@ -2584,20 +2564,18 @@ int rtnl_link_set_type(struct rtnl_link *link, const char *type)
io = rtnl_link_info_ops_lookup(type);
if (io) {
- if (io->io_alloc && (err = io->io_alloc(link)) < 0)
- goto errout;
+ if (io->io_alloc && (err = io->io_alloc(link)) < 0) {
+ _nl_clear_free(&kind);
+ return err;
+ }
link->l_info_ops = io;
}
- link->l_info_kind = kind;
+ link->l_info_kind = _nl_steal_pointer(&kind);
link->ce_mask |= LINK_ATTR_LINKINFO;
return 0;
-
-errout:
- free(kind);
- return err;
}
/**
@@ -2857,7 +2835,7 @@ pid_t rtnl_link_get_ns_pid(struct rtnl_link *link)
*/
int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
{
- struct rtnl_link *link;
+ _nl_auto_rtnl_link struct rtnl_link *link = NULL;
int err;
if (!(link = rtnl_link_alloc()))
@@ -2867,12 +2845,12 @@ int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
rtnl_link_set_master(link, master);
if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
- goto errout;
+ return err;
- rtnl_link_put(link);
+ _nl_clear_pointer(&link, rtnl_link_put);
/*
- * Due to the kernel not signaling whether this opertion is
+ * Due to the kernel not signaling whether this operation is
* supported or not, we will retrieve the attribute to see if the
* request was successful. If the master assigned remains unchanged
* we will return NLE_OPNOTSUPP to allow performing backwards
@@ -2882,12 +2860,9 @@ int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
return err;
if (rtnl_link_get_master(link) != master)
- err = -NLE_OPNOTSUPP;
-
-errout:
- rtnl_link_put(link);
+ return -NLE_OPNOTSUPP;
- return err;
+ return 0;
}
/**
@@ -3063,6 +3038,7 @@ static const struct trans_tbl link_stats[] = {
__ADD(RTNL_LINK_IP6_ECT0PKTS, Ip6_InECT0Pkts),
__ADD(RTNL_LINK_IP6_CEPKTS, Ip6_InCEPkts),
__ADD(RTNL_LINK_RX_NOHANDLER, rx_nohandler),
+ __ADD(RTNL_LINK_REASM_OVERLAPS, ReasmOverlaps),
};
char *rtnl_link_stat2str(int st, char *buf, size_t len)
@@ -3135,22 +3111,16 @@ int rtnl_link_has_vf_list(struct rtnl_link *link) {
return 0;
}
-void rtnl_link_set_vf_list(struct rtnl_link *link) {
- int err;
-
- if (!(err = rtnl_link_has_vf_list(link)))
+void rtnl_link_set_vf_list(struct rtnl_link *link)
+{
+ if (!rtnl_link_has_vf_list(link))
link->ce_mask |= LINK_ATTR_VF_LIST;
-
- return;
}
-void rtnl_link_unset_vf_list(struct rtnl_link *link) {
- int err;
-
- if ((err = rtnl_link_has_vf_list(link)))
+void rtnl_link_unset_vf_list(struct rtnl_link *link)
+{
+ if (rtnl_link_has_vf_list(link))
link->ce_mask &= ~LINK_ATTR_VF_LIST;
-
- return;
}
/** @} */
@@ -3213,6 +3183,7 @@ static struct nl_object_ops link_obj_ops = {
static struct nl_af_group link_groups[] = {
{ AF_UNSPEC, RTNLGRP_LINK },
{ AF_BRIDGE, RTNLGRP_LINK },
+ { AF_INET6, RTNLGRP_IPV6_IFINFO },
{ END_OF_GROUP_LIST },
};
diff --git a/lib/route/link/api.c b/lib/route/link/api.c
index d406783e..cd2c42bb 100644
--- a/lib/route/link/api.c
+++ b/lib/route/link/api.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/api.c Link Info API
- *
- * 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-2008 Thomas Graf <tgraf@suug.ch>
*/
@@ -87,13 +81,32 @@ struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
}
/**
+ * Take reference to a set of operations.
+ * @arg ops Link info operations.
+ */
+void rtnl_link_info_ops_get(struct rtnl_link_info_ops *ops)
+{
+ if (!ops)
+ return;
+
+ nl_write_lock(&info_lock);
+ ops->io_refcnt++;
+ nl_write_unlock(&info_lock);
+}
+
+/**
* Give back reference to a set of operations.
* @arg ops Link info operations.
*/
void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops)
{
- if (ops)
- ops->io_refcnt--;
+ if (!ops)
+ return;
+
+ nl_write_lock(&info_lock);
+ _nl_assert(ops->io_refcnt > 0);
+ ops->io_refcnt--;
+ nl_write_unlock(&info_lock);
}
/**
@@ -152,6 +165,7 @@ int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
nl_list_for_each_entry(t, &info_ops, io_list) {
if (t == ops) {
+ _nl_assert(t->io_refcnt >= 0);
if (t->io_refcnt > 0) {
err = -NLE_BUSY;
goto errout;
@@ -208,8 +222,11 @@ struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family)
*/
void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops)
{
- if (ops)
+ if (ops) {
+ nl_write_lock(&info_lock);
ops->ao_refcnt--;
+ nl_write_unlock(&info_lock);
+ }
}
/**
diff --git a/lib/route/link/bonding.c b/lib/route/link/bonding.c
index 11b6d3d1..90e64703 100644
--- a/lib/route/link/bonding.c
+++ b/lib/route/link/bonding.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/bonding.c Bonding Link Module
- *
- * 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) 2011-2013 Thomas Graf <tgraf@suug.ch>
*/
@@ -33,12 +27,11 @@
struct rtnl_link *rtnl_link_bond_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "bond")) < 0) {
+ if (rtnl_link_set_type(link, "bond") < 0) {
rtnl_link_put(link);
return NULL;
}
diff --git a/lib/route/link/bridge.c b/lib/route/link/bridge.c
index 2d95faf8..bd042539 100644
--- a/lib/route/link/bridge.c
+++ b/lib/route/link/bridge.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/bridge.c AF_BRIDGE link support
- *
- * 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>
*/
@@ -464,12 +458,11 @@ static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
struct rtnl_link *rtnl_link_bridge_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "bridge")) < 0) {
+ if (rtnl_link_set_type(link, "bridge") < 0) {
rtnl_link_put(link);
return NULL;
}
diff --git a/lib/route/link/can.c b/lib/route/link/can.c
index 884121f9..da8f092d 100644
--- a/lib/route/link/can.c
+++ b/lib/route/link/can.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/can.c CAN Link Info
- *
- * 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) 2012 Benedikt Spranger <b.spranger@linutronix.de>
*/
@@ -42,6 +36,8 @@
#define CAN_HAS_RESTART_MS (1<<5)
#define CAN_HAS_RESTART (1<<6)
#define CAN_HAS_BERR_COUNTER (1<<7)
+#define CAN_HAS_DATA_BITTIMING (1<<8)
+#define CAN_HAS_DATA_BITTIMING_CONST (1<<9)
struct can_info {
uint32_t ci_state;
@@ -53,6 +49,8 @@ struct can_info {
struct can_clock ci_clock;
struct can_berr_counter ci_berr_counter;
uint32_t ci_mask;
+ struct can_bittiming ci_data_bittiming;
+ struct can_bittiming_const ci_data_bittiming_const;
};
/** @endcond */
@@ -67,6 +65,10 @@ static struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
= { .minlen = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .minlen = sizeof(struct can_clock) },
[IFLA_CAN_BERR_COUNTER] = { .minlen = sizeof(struct can_berr_counter) },
+ [IFLA_CAN_DATA_BITTIMING]
+ = { .minlen = sizeof(struct can_bittiming) },
+ [IFLA_CAN_DATA_BITTIMING_CONST]
+ = { .minlen = sizeof(struct can_bittiming_const) },
};
static int can_alloc(struct rtnl_link *link)
@@ -149,6 +151,18 @@ static int can_parse(struct rtnl_link *link, struct nlattr *data,
ci->ci_mask |= CAN_HAS_BERR_COUNTER;
}
+ if (tb[IFLA_CAN_DATA_BITTIMING]) {
+ nla_memcpy(&ci->ci_data_bittiming, tb[IFLA_CAN_DATA_BITTIMING],
+ sizeof(ci->ci_data_bittiming));
+ ci->ci_mask |= CAN_HAS_DATA_BITTIMING;
+ }
+
+ if (tb[IFLA_CAN_DATA_BITTIMING_CONST]) {
+ nla_memcpy(&ci->ci_data_bittiming_const, tb[IFLA_CAN_DATA_BITTIMING_CONST],
+ sizeof(ci->ci_data_bittiming_const));
+ ci->ci_mask |= CAN_HAS_DATA_BITTIMING_CONST;
+ }
+
err = 0;
errout:
return err;
@@ -259,7 +273,7 @@ static void can_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
}
if (ci->ci_mask & CAN_HAS_CLOCK) {
- nl_dump_line(p," base freq %d Hz\n", ci->ci_clock);
+ nl_dump_line(p," base freq %u Hz\n", ci->ci_clock.freq);
}
@@ -303,28 +317,36 @@ static int can_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
return -NLE_MSGSIZE;
if (ci->ci_mask & CAN_HAS_RESTART)
- NLA_PUT_U32(msg, CAN_HAS_RESTART, ci->ci_restart);
+ NLA_PUT_U32(msg, IFLA_CAN_RESTART, ci->ci_restart);
if (ci->ci_mask & CAN_HAS_RESTART_MS)
- NLA_PUT_U32(msg, CAN_HAS_RESTART_MS, ci->ci_restart_ms);
+ NLA_PUT_U32(msg, IFLA_CAN_RESTART_MS, ci->ci_restart_ms);
if (ci->ci_mask & CAN_HAS_CTRLMODE)
- NLA_PUT(msg, CAN_HAS_CTRLMODE, sizeof(ci->ci_ctrlmode),
+ NLA_PUT(msg, IFLA_CAN_CTRLMODE, sizeof(ci->ci_ctrlmode),
&ci->ci_ctrlmode);
if (ci->ci_mask & CAN_HAS_BITTIMING)
- NLA_PUT(msg, CAN_HAS_BITTIMING, sizeof(ci->ci_bittiming),
+ NLA_PUT(msg, IFLA_CAN_BITTIMING, sizeof(ci->ci_bittiming),
&ci->ci_bittiming);
if (ci->ci_mask & CAN_HAS_BITTIMING_CONST)
- NLA_PUT(msg, CAN_HAS_BITTIMING_CONST,
+ NLA_PUT(msg, IFLA_CAN_BITTIMING_CONST,
sizeof(ci->ci_bittiming_const),
&ci->ci_bittiming_const);
if (ci->ci_mask & CAN_HAS_CLOCK)
- NLA_PUT(msg, CAN_HAS_CLOCK, sizeof(ci->ci_clock),
+ NLA_PUT(msg, IFLA_CAN_CLOCK, sizeof(ci->ci_clock),
&ci->ci_clock);
+ if (ci->ci_mask & CAN_HAS_DATA_BITTIMING)
+ NLA_PUT(msg, IFLA_CAN_DATA_BITTIMING, sizeof(ci->ci_data_bittiming),
+ &ci->ci_data_bittiming);
+
+ if (ci->ci_mask & CAN_HAS_DATA_BITTIMING_CONST)
+ NLA_PUT(msg, IFLA_CAN_DATA_BITTIMING_CONST, sizeof(ci->ci_data_bittiming_const),
+ &ci->ci_data_bittiming_const);
+
nla_nest_end(msg, data);
nla_put_failure:
@@ -489,7 +511,7 @@ int rtnl_link_can_berr(struct rtnl_link *link, struct can_berr_counter *berr)
}
/**
- * Get CAN harware-dependent bit-timing constant
+ * Get CAN hardware-dependent bit-timing constant
* @arg link Link object
* @arg bt_const Bit-timing constant
*
@@ -544,7 +566,7 @@ int rtnl_link_can_get_bittiming(struct rtnl_link *link,
* @return 0 on success or a negative error code
*/
int rtnl_link_can_set_bittiming(struct rtnl_link *link,
- struct can_bittiming *bit_timing)
+ const struct can_bittiming *bit_timing)
{
struct can_info *ci = link->l_info;
@@ -747,6 +769,98 @@ int rtnl_link_can_unset_ctrlmode(struct rtnl_link *link, uint32_t ctrlmode)
return 0;
}
+/**
+ * Get CAN FD hardware-dependent data bit-timing constant
+ * @arg link Link object
+ * @arg data_bt_const CAN FD data bit-timing constant
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_get_data_bittiming_const(struct rtnl_link *link,
+ struct can_bittiming_const *data_bt_const)
+{
+ struct can_info *ci = link->l_info;
+
+ IS_CAN_LINK_ASSERT(link);
+ if (!data_bt_const)
+ return -NLE_INVAL;
+
+ if (ci->ci_mask & CAN_HAS_DATA_BITTIMING_CONST)
+ *data_bt_const = ci->ci_data_bittiming_const;
+ else
+ return -NLE_AGAIN;
+
+ return 0;
+}
+
+/**
+ * Set CAN FD device data bit-timing-const
+ * @arg link Link object
+ * @arg data_bit_timing CAN FD data bit-timing
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_set_data_bittiming_const(struct rtnl_link *link,
+ const struct can_bittiming_const *data_bt_const)
+{
+ struct can_info *ci = link->l_info;
+
+ IS_CAN_LINK_ASSERT(link);
+ if (!data_bt_const)
+ return -NLE_INVAL;
+
+ ci->ci_data_bittiming_const = *data_bt_const;
+ ci->ci_mask |= CAN_HAS_DATA_BITTIMING_CONST;
+
+ return 0;
+}
+
+/**
+ * Get CAN FD device data bit-timing
+ * @arg link Link object
+ * @arg data_bit_timing CAN FD data bit-timing
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_get_data_bittiming(struct rtnl_link *link,
+ struct can_bittiming *data_bit_timing)
+{
+ struct can_info *ci = link->l_info;
+
+ IS_CAN_LINK_ASSERT(link);
+ if (!data_bit_timing)
+ return -NLE_INVAL;
+
+ if (ci->ci_mask & CAN_HAS_DATA_BITTIMING)
+ *data_bit_timing = ci->ci_data_bittiming;
+ else
+ return -NLE_AGAIN;
+
+ return 0;
+}
+
+/**
+ * Set CAN FD device data bit-timing
+ * @arg link Link object
+ * @arg data_bit_timing CAN FD data bit-timing
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_set_data_bittiming(struct rtnl_link *link,
+ const struct can_bittiming *data_bit_timing)
+{
+ struct can_info *ci = link->l_info;
+
+ IS_CAN_LINK_ASSERT(link);
+ if (!data_bit_timing)
+ return -NLE_INVAL;
+
+ ci->ci_data_bittiming = *data_bit_timing;
+ ci->ci_mask |= CAN_HAS_DATA_BITTIMING;
+
+ return 0;
+}
+
/** @} */
/**
@@ -760,6 +874,9 @@ static const struct trans_tbl can_ctrlmode[] = {
__ADD(CAN_CTRLMODE_3_SAMPLES, triple-sampling),
__ADD(CAN_CTRLMODE_ONE_SHOT, one-shot),
__ADD(CAN_CTRLMODE_BERR_REPORTING, berr-reporting),
+ __ADD(CAN_CTRLMODE_FD, fd),
+ __ADD(CAN_CTRLMODE_PRESUME_ACK, presume-ack),
+ __ADD(CAN_CTRLMODE_FD_NON_ISO, fd-non-iso),
};
char *rtnl_link_can_ctrlmode2str(int ctrlmode, char *buf, size_t len)
diff --git a/lib/route/link/dummy.c b/lib/route/link/dummy.c
index 1fd9f5a3..a6478d00 100644
--- a/lib/route/link/dummy.c
+++ b/lib/route/link/dummy.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/dummy.c Dummy Interfaces
- *
- * 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) 2011 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/link/geneve.c b/lib/route/link/geneve.c
index 7232b07f..cab57cc0 100644
--- a/lib/route/link/geneve.c
+++ b/lib/route/link/geneve.c
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/geneve.c Geneve Link Info
- * 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) 2018 Wang Jian <jianjian.wang1@gmail.com>
*/
+
/**
* @ingroup link
* @defgroup geneve Geneve
@@ -190,16 +186,12 @@ static void geneve_dump_details(struct rtnl_link *link, struct nl_dump_params *p
if (geneve->mask & GENEVE_ATTR_REMOTE) {
nl_dump(p, " remote ");
- if (inet_ntop(AF_INET, &geneve->remote, addr, sizeof(addr)))
- nl_dump_line(p, "%s\n", addr);
- else
- nl_dump_line(p, "%#x\n", ntohs(geneve->remote));
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET, &geneve->remote, addr));
} else if (geneve->mask & GENEVE_ATTR_REMOTE6) {
nl_dump(p, " remote ");
- if (inet_ntop(AF_INET6, &geneve->remote6, addr, sizeof(addr)))
- nl_dump_line(p, "%s\n", addr);
- else
- nl_dump_line(p, "%#x\n", geneve->remote6);
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &geneve->remote6, addr));
}
if (geneve->mask & GENEVE_ATTR_TTL) {
@@ -240,7 +232,7 @@ static void geneve_dump_details(struct rtnl_link *link, struct nl_dump_params *p
if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_RX) {
nl_dump(p, " udp-zero-csum6-rx ");
- if (geneve->udp_zero_csum6_tx)
+ if (geneve->udp_zero_csum6_rx)
nl_dump_line(p, "enabled (%#x)\n", geneve->udp_zero_csum6_rx);
else
nl_dump_line(p, "disabled\n");
@@ -356,12 +348,11 @@ static struct rtnl_link_info_ops geneve_info_ops = {
struct rtnl_link *rtnl_link_geneve_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "geneve")) < 0) {
+ if (rtnl_link_set_type(link, "geneve") < 0) {
rtnl_link_put(link);
return NULL;
}
diff --git a/lib/route/link/ifb.c b/lib/route/link/ifb.c
index 524f5c6a..528647e0 100644
--- a/lib/route/link/ifb.c
+++ b/lib/route/link/ifb.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/ifb.c IFB Interfaces
- *
- * 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) 2014 Cong Wang <xiyou.wangcong@gmail.com>
*/
diff --git a/lib/route/link/inet.c b/lib/route/link/inet.c
index 6651bc38..2f95fb6e 100644
--- a/lib/route/link/inet.c
+++ b/lib/route/link/inet.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/inet.c AF_INET link operations
- *
- * 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 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/link/inet6.c b/lib/route/link/inet6.c
index f02792c8..afcbbceb 100644
--- a/lib/route/link/inet6.c
+++ b/lib/route/link/inet6.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/inet6.c AF_INET6 link operations
- *
- * 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 Thomas Graf <tgraf@suug.ch>
*/
@@ -16,6 +10,7 @@
#include <netlink/route/link/inet6.h>
#include <netlink-private/route/link/api.h>
+#include "netlink-private/route/utils.h"
#include "netlink-private/utils.h"
#define I6_ADDR_GEN_MODE_UNKNOWN UINT8_MAX
@@ -141,8 +136,11 @@ static const uint8_t map_stat_id_from_IPSTATS_MIB_v2[__IPSTATS_MIB_MAX] = {
[33] = RTNL_LINK_IP6_ECT1PKTS, /* IPSTATS_MIB_ECT1PKTS */
[34] = RTNL_LINK_IP6_ECT0PKTS, /* IPSTATS_MIB_ECT0PKTS */
[35] = RTNL_LINK_IP6_CEPKTS, /* IPSTATS_MIB_CEPKTS */
+ [36] = RTNL_LINK_REASM_OVERLAPS, /* IPSTATS_MIB_REASM_OVERLAPS */
};
+const uint8_t *const _nltst_map_stat_id_from_IPSTATS_MIB_v2 = map_stat_id_from_IPSTATS_MIB_v2;
+
static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
void *data)
{
@@ -212,6 +210,9 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
int i;
int len = min_t(int, __ICMP6_MIB_MAX, nla_len(tb[IFLA_INET6_ICMP6STATS]) / 8);
+ _NL_STATIC_ASSERT (__ICMP6_MIB_MAX == 6);
+ _NL_STATIC_ASSERT (RTNL_LINK_ICMP6_CSUMERRORS - RTNL_LINK_ICMP6_INMSGS + 1 == 5);
+
for (i = 1; i < len; i++) {
memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS + i - 1,
@@ -412,7 +413,7 @@ static void inet6_dump_stats(struct rtnl_link *link,
if (octets)
nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
else
- nl_dump(p, "%16" PRIu64 " B ", 0);
+ nl_dump(p, "%16u B ", 0);
nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
link->l_stats[RTNL_LINK_IP6_INDISCARDS],
@@ -428,7 +429,7 @@ static void inet6_dump_stats(struct rtnl_link *link,
if (octets)
nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
else
- nl_dump(p, "%16" PRIu64 " B ", 0);
+ nl_dump(p, "%16u B ", 0);
nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
link->l_stats[RTNL_LINK_IP6_OUTDISCARDS],
@@ -444,7 +445,7 @@ static void inet6_dump_stats(struct rtnl_link *link,
if (octets)
nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
else
- nl_dump(p, "%16" PRIu64 " B ", 0);
+ nl_dump(p, "%16u B ", 0);
nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]);
octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS],
@@ -452,7 +453,7 @@ static void inet6_dump_stats(struct rtnl_link *link,
if (octets)
nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
else
- nl_dump(p, "%16" PRIu64 " B\n", 0);
+ nl_dump(p, "%16u B\n", 0);
nl_dump(p, " OutMcastPkts OutMcastOctets "
" OutBcastPkts OutBcastOctests\n");
@@ -464,7 +465,7 @@ static void inet6_dump_stats(struct rtnl_link *link,
if (octets)
nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
else
- nl_dump(p, "%16" PRIu64 " B ", 0);
+ nl_dump(p, "%16u B ", 0);
nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]);
octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS],
@@ -472,7 +473,7 @@ static void inet6_dump_stats(struct rtnl_link *link,
if (octets)
nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
else
- nl_dump(p, "%16" PRIu64 " B\n", 0);
+ nl_dump(p, "%16u B\n", 0);
nl_dump(p, " ReasmOKs ReasmFails "
" ReasmReqds ReasmTimeout\n");
diff --git a/lib/route/link/ip6gre.c b/lib/route/link/ip6gre.c
new file mode 100644
index 00000000..5d5c3a01
--- /dev/null
+++ b/lib/route/link/ip6gre.c
@@ -0,0 +1,886 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+
+/**
+ * @ingroup link
+ * @defgroup ip6gre IP6GRE
+ * ip6gre link module
+ *
+ * @details
+ * \b Link Type Name: "ip6gre"
+ *
+ * @route_doc{link_ip6gre, IP6GRE Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/ip6gre.h>
+#include <netlink-private/route/link/api.h>
+#include <linux/if_tunnel.h>
+
+#define IP6GRE_ATTR_LINK (1 << 0)
+#define IP6GRE_ATTR_IFLAGS (1 << 1)
+#define IP6GRE_ATTR_OFLAGS (1 << 2)
+#define IP6GRE_ATTR_IKEY (1 << 3)
+#define IP6GRE_ATTR_OKEY (1 << 4)
+#define IP6GRE_ATTR_LOCAL (1 << 5)
+#define IP6GRE_ATTR_REMOTE (1 << 6)
+#define IP6GRE_ATTR_TTL (1 << 7)
+#define IP6GRE_ATTR_ENCAPLIMIT (1 << 8)
+#define IP6GRE_ATTR_FLOWINFO (1 << 9)
+#define IP6GRE_ATTR_FLAGS (1 << 10)
+#define IP6GRE_ATTR_FWMARK (1 << 11)
+
+struct ip6gre_info
+{
+ uint8_t ttl;
+ uint8_t encaplimit;
+ uint16_t iflags;
+ uint16_t oflags;
+ uint32_t ikey;
+ uint32_t okey;
+ uint32_t link;
+ uint32_t flowinfo;
+ uint32_t flags;
+ struct in6_addr local;
+ struct in6_addr remote;
+ uint32_t fwmark;
+ uint32_t ip6gre_mask;
+};
+
+static struct nla_policy ip6gre_policy[IFLA_GRE_MAX + 1] = {
+ [IFLA_GRE_LINK] = { .type = NLA_U32 },
+ [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
+ [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
+ [IFLA_GRE_IKEY] = { .type = NLA_U32 },
+ [IFLA_GRE_OKEY] = { .type = NLA_U32 },
+ [IFLA_GRE_LOCAL] = { .minlen = sizeof(struct in6_addr) },
+ [IFLA_GRE_REMOTE] = { .minlen = sizeof(struct in6_addr) },
+ [IFLA_GRE_TTL] = { .type = NLA_U8 },
+ [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 },
+ [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 },
+ [IFLA_GRE_FLAGS] = { .type = NLA_U32 },
+ [IFLA_GRE_FWMARK] = { .type = NLA_U32 },
+};
+
+static int ip6gre_alloc(struct rtnl_link *link)
+{
+ struct ip6gre_info *ip6gre;
+
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*ip6gre));
+ else {
+ ip6gre = calloc(1, sizeof(*ip6gre));
+ if (!ip6gre)
+ return -NLE_NOMEM;
+
+ link->l_info = ip6gre;
+ }
+
+ return 0;
+}
+
+static int ip6gre_parse(struct rtnl_link *link, struct nlattr *data,
+ struct nlattr *xstats)
+{
+ struct nlattr *tb[IFLA_GRE_MAX + 1];
+ struct ip6gre_info *ip6gre;
+ int err;
+
+ NL_DBG(3, "Parsing IP6GRE link info\n");
+
+ err = nla_parse_nested(tb, IFLA_GRE_MAX, data, ip6gre_policy);
+ if (err < 0)
+ goto errout;
+
+ err = ip6gre_alloc(link);
+ if (err < 0)
+ goto errout;
+
+ ip6gre = link->l_info;
+
+ if (tb[IFLA_GRE_LINK]) {
+ ip6gre->link = nla_get_u32(tb[IFLA_GRE_LINK]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_LINK;
+ }
+
+ if (tb[IFLA_GRE_IFLAGS]) {
+ ip6gre->iflags = nla_get_u16(tb[IFLA_GRE_IFLAGS]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_IFLAGS;
+ }
+
+ if (tb[IFLA_GRE_OFLAGS]) {
+ ip6gre->oflags = nla_get_u16(tb[IFLA_GRE_OFLAGS]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_OFLAGS;
+ }
+
+ if (tb[IFLA_GRE_IKEY]) {
+ ip6gre->ikey = nla_get_u32(tb[IFLA_GRE_IKEY]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_IKEY;
+ }
+
+ if (tb[IFLA_GRE_OKEY]) {
+ ip6gre->okey = nla_get_u32(tb[IFLA_GRE_OKEY]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_OKEY;
+ }
+
+ if (tb[IFLA_GRE_LOCAL]) {
+ nla_memcpy(&ip6gre->local, tb[IFLA_GRE_LOCAL], sizeof(struct in6_addr));
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_LOCAL;
+ }
+
+ if (tb[IFLA_GRE_REMOTE]) {
+ nla_memcpy(&ip6gre->remote, tb[IFLA_GRE_REMOTE], sizeof(struct in6_addr));
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_REMOTE;
+ }
+
+ if (tb[IFLA_GRE_TTL]) {
+ ip6gre->ttl = nla_get_u8(tb[IFLA_GRE_TTL]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_TTL;
+ }
+
+ if (tb[IFLA_GRE_ENCAP_LIMIT]) {
+ ip6gre->encaplimit = nla_get_u8(tb[IFLA_GRE_ENCAP_LIMIT]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_ENCAPLIMIT;
+ }
+
+ if (tb[IFLA_GRE_FLOWINFO]) {
+ ip6gre->flowinfo = nla_get_u32(tb[IFLA_GRE_FLOWINFO]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_FLOWINFO;
+ }
+
+ if (tb[IFLA_GRE_FLAGS]) {
+ ip6gre->flags = nla_get_u32(tb[IFLA_GRE_FLAGS]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_FLAGS;
+ }
+
+ if (tb[IFLA_GRE_FWMARK]) {
+ ip6gre->fwmark = nla_get_u32(tb[IFLA_GRE_FWMARK]);
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_FWMARK;
+ }
+
+ err = 0;
+
+ errout:
+ return err;
+}
+
+static int ip6gre_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+ struct nlattr *data;
+
+ data = nla_nest_start(msg, IFLA_INFO_DATA);
+ if (!data)
+ return -NLE_MSGSIZE;
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_LINK)
+ NLA_PUT_U32(msg, IFLA_GRE_LINK, ip6gre->link);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_IFLAGS)
+ NLA_PUT_U16(msg, IFLA_GRE_IFLAGS, ip6gre->iflags);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_OFLAGS)
+ NLA_PUT_U16(msg, IFLA_GRE_OFLAGS, ip6gre->oflags);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_IKEY)
+ NLA_PUT_U32(msg, IFLA_GRE_IKEY, ip6gre->ikey);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_OKEY)
+ NLA_PUT_U32(msg, IFLA_GRE_OKEY, ip6gre->okey);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_LOCAL)
+ NLA_PUT(msg, IFLA_GRE_LOCAL, sizeof(struct in6_addr), &ip6gre->local);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_REMOTE)
+ NLA_PUT(msg, IFLA_GRE_REMOTE, sizeof(struct in6_addr), &ip6gre->remote);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_TTL)
+ NLA_PUT_U8(msg, IFLA_GRE_TTL, ip6gre->ttl);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_ENCAPLIMIT)
+ NLA_PUT_U8(msg, IFLA_GRE_ENCAP_LIMIT, ip6gre->encaplimit);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FLOWINFO)
+ NLA_PUT_U32(msg, IFLA_GRE_FLOWINFO, ip6gre->flowinfo);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FLAGS)
+ NLA_PUT_U32(msg, IFLA_GRE_FLAGS, ip6gre->flags);
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FWMARK)
+ NLA_PUT_U32(msg, IFLA_GRE_FWMARK, ip6gre->fwmark);
+
+ nla_nest_end(msg, data);
+
+ nla_put_failure:
+
+ return 0;
+}
+
+static void ip6gre_free(struct rtnl_link *link)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ free(ip6gre);
+ link->l_info = NULL;
+}
+
+static void ip6gre_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ nl_dump(p, "ip6gre : %s", link->l_name);
+}
+
+static void ip6gre_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+ char *name;
+ char addr[INET6_ADDRSTRLEN];
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_LINK) {
+ nl_dump(p, " link ");
+ name = rtnl_link_get_name(link);
+ if (name)
+ nl_dump_line(p, "%s\n", name);
+ else
+ nl_dump_line(p, "%u\n", ip6gre->link);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_IFLAGS) {
+ nl_dump(p, " iflags ");
+ nl_dump_line(p, "%x\n", ip6gre->iflags);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_OFLAGS) {
+ nl_dump(p, " oflags ");
+ nl_dump_line(p, "%x\n", ip6gre->oflags);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_IKEY) {
+ nl_dump(p, " ikey ");
+ nl_dump_line(p, "%x\n",ip6gre->ikey);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_OKEY) {
+ nl_dump(p, " okey ");
+ nl_dump_line(p, "%x\n", ip6gre->okey);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_LOCAL) {
+ nl_dump(p, " local ");
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &ip6gre->local, addr));
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_REMOTE) {
+ nl_dump(p, " remote ");
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &ip6gre->remote, addr));
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_TTL) {
+ nl_dump(p, " ttl ");
+ nl_dump_line(p, "%u\n", ip6gre->ttl);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_ENCAPLIMIT) {
+ nl_dump(p, " encaplimit ");
+ nl_dump_line(p, "%u\n", ip6gre->encaplimit);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FLOWINFO) {
+ nl_dump(p, " flowinfo ");
+ nl_dump_line(p, "%x\n", ip6gre->flowinfo);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FLAGS) {
+ nl_dump(p, " flags ");
+ nl_dump_line(p, "%x\n", ip6gre->flags);
+ }
+
+ if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FWMARK) {
+ nl_dump(p, " fwmark ");
+ nl_dump_line(p, "%x\n", ip6gre->fwmark);
+ }
+}
+
+static int ip6gre_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct ip6gre_info *ip6gre_dst, *ip6gre_src = src->l_info;
+ int err;
+
+ dst->l_info = NULL;
+
+ err = rtnl_link_set_type(dst, "ip6gre");
+ if (err < 0)
+ return err;
+
+ ip6gre_dst = dst->l_info;
+
+ if (!ip6gre_dst || !ip6gre_src)
+ BUG();
+
+ memcpy(ip6gre_dst, ip6gre_src, sizeof(struct ip6gre_info));
+
+ return 0;
+}
+
+static struct rtnl_link_info_ops ip6gre_info_ops = {
+ .io_name = "ip6gre",
+ .io_alloc = ip6gre_alloc,
+ .io_parse = ip6gre_parse,
+ .io_dump = {
+ [NL_DUMP_LINE] = ip6gre_dump_line,
+ [NL_DUMP_DETAILS] = ip6gre_dump_details,
+ },
+ .io_clone = ip6gre_clone,
+ .io_put_attrs = ip6gre_put_attrs,
+ .io_free = ip6gre_free,
+};
+
+#define IS_IP6GRE_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &ip6gre_info_ops) { \
+ APPBUG("Link is not a ip6gre link. set type \"ip6gre\" first.");\
+ return -NLE_OPNOTSUPP; \
+ }
+
+#define HAS_IP6GRE_ATTR_ASSERT(link,attr) \
+ if (!((link)->ip6gre_mask & (attr))) \
+ return -NLE_NOATTR;
+
+struct rtnl_link *rtnl_link_ip6gre_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ link = rtnl_link_alloc();
+ if (!link)
+ return NULL;
+
+ err = rtnl_link_set_type(link, "ip6gre");
+ if (err < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Check if link is a IP6GRE link
+ * @arg link Link object
+ *
+ * @return True if link is a IP6GRE link, otherwise 0 is returned.
+ */
+int rtnl_link_is_ip6gre(struct rtnl_link *link)
+{
+ return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ip6gre");
+}
+
+/**
+ * Create a new IP6GRE tunnel device
+ * @arg sock netlink socket
+ * @arg name name of the tunnel deviceL
+ *
+ * Creates a new ip6gre tunnel device in the kernel
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_add(struct nl_sock *sk, const char *name)
+{
+ struct rtnl_link *link;
+ int err;
+
+ link = rtnl_link_ip6gre_alloc();
+ if (!link)
+ return -NLE_NOMEM;
+
+ if(name)
+ rtnl_link_set_name(link, name);
+
+ err = rtnl_link_add(sk, link, NLM_F_CREATE);
+ rtnl_link_put(link);
+
+ return err;
+}
+
+/**
+ * Set IP6GRE tunnel interface index
+ * @arg link Link object
+ * @arg index interface index
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_link(struct rtnl_link *link, uint32_t index)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->link = index;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_LINK;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel interface index
+ * @arg link Link object
+ * @arg index addr to fill in with the interface index
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_link(struct rtnl_link *link, uint32_t *index)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_LINK);
+
+ *index = ip6gre->link;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel set iflags
+ * @arg link Link object
+ * @arg iflags ip6gre iflags
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_iflags(struct rtnl_link *link, uint16_t iflags)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->iflags = iflags;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_IFLAGS;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel iflags
+ * @arg link Link object
+ * @arg iflags addr to fill in with the iflags
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_iflags(struct rtnl_link *link, uint16_t *iflags)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_IFLAGS);
+
+ *iflags = ip6gre->iflags;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel set oflags
+ * @arg link Link object
+ * @arg oflags ip6gre oflags
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_oflags(struct rtnl_link *link, uint16_t oflags)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->oflags = oflags;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_OFLAGS;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel oflags
+ * @arg link Link object
+ * @arg oflags addr to fill in with the oflags
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_oflags(struct rtnl_link *link, uint16_t *oflags)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_OFLAGS);
+
+ *oflags = ip6gre->oflags;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel set ikey
+ * @arg link Link object
+ * @arg ikey ip6gre ikey
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_ikey(struct rtnl_link *link, uint32_t ikey)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->ikey = ikey;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_IKEY;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel ikey
+ * @arg link Link object
+ * @arg ikey addr to fill in with the ikey
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_ikey(struct rtnl_link *link, uint32_t *ikey)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_IKEY);
+
+ *ikey = ip6gre->ikey;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel set okey
+ * @arg link Link object
+ * @arg okey ip6gre okey
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_okey(struct rtnl_link *link, uint32_t okey)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->okey = okey;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_OKEY;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel okey
+ * @arg link Link object
+ * @arg okey addr to fill in with the okey
+ *
+ * @return okey value
+ */
+int rtnl_link_ip6gre_get_okey(struct rtnl_link *link, uint32_t *okey)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_OKEY);
+
+ *okey = ip6gre->okey;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel local address
+ * @arg link Link object
+ * @arg local local address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_local(struct rtnl_link *link, struct in6_addr *local)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ memcpy(&ip6gre->local, local, sizeof(struct in6_addr));
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_LOCAL;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel local address
+ * @arg link Link object
+ * @arg local addr to fill in with local address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_local(struct rtnl_link *link, struct in6_addr *local)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_LOCAL);
+
+ memcpy(local, &ip6gre->local, sizeof(struct in6_addr));
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel remote address
+ * @arg link Link object
+ * @arg remote remote address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_remote(struct rtnl_link *link, struct in6_addr *remote)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ memcpy(&ip6gre->remote, remote, sizeof(struct in6_addr));
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_REMOTE;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel remote address
+ * @arg link Link object
+ * @arg remote addr to fill in with remote address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_remote(struct rtnl_link *link, struct in6_addr *remote)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_REMOTE);
+
+ memcpy(remote, &ip6gre->remote, sizeof(struct in6_addr));
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel ttl
+ * @arg link Link object
+ * @arg ttl tunnel ttl
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_ttl(struct rtnl_link *link, uint8_t ttl)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->ttl = ttl;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_TTL;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel ttl
+ * @arg link Link object
+ * @arg ttl addr to fill in with the ttl
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_ttl(struct rtnl_link *link, uint8_t *ttl)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_TTL);
+
+ *ttl = ip6gre->ttl;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel encap limit
+ * @arg link Link object
+ * @arg encaplimit tunnel encap limit value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_encaplimit(struct rtnl_link *link, uint8_t encaplimit)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->encaplimit = encaplimit;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_ENCAPLIMIT;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel encap limit
+ * @arg link Link object
+ * @arg encaplimit addr to fill in with the encaplimit
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_encaplimit(struct rtnl_link *link, uint8_t *encaplimit)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_ENCAPLIMIT);
+
+ *encaplimit = ip6gre->encaplimit;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel flowinfo
+ * @arg link Link object
+ * @arg flowinfo flowinfo value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_flowinfo(struct rtnl_link *link, uint32_t flowinfo)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->flowinfo = flowinfo;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_FLOWINFO;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE flowinfo
+ * @arg link Link object
+ * @arg flowinfo addr to fill in with the flowinfo
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_flowinfo(struct rtnl_link *link, uint32_t *flowinfo)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_FLOWINFO);
+
+ *flowinfo = ip6gre->flowinfo;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel flags
+ * @arg link Link object
+ * @arg flags tunnel flags
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_flags(struct rtnl_link *link, uint32_t flags)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->flags = flags;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_FLAGS;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE flags
+ * @arg link Link object
+ * @arg flags addr to fill in with the tunnel flags
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_flags(struct rtnl_link *link, uint32_t *flags)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_FLAGS);
+
+ *flags = ip6gre->flags;
+
+ return 0;
+}
+
+/**
+ * Set IP6GRE tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ ip6gre->fwmark = fwmark;
+ ip6gre->ip6gre_mask |= IP6GRE_ATTR_FWMARK;
+
+ return 0;
+}
+
+/**
+ * Get IP6GRE tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark addr to fill in with the fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6gre_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
+{
+ struct ip6gre_info *ip6gre = link->l_info;
+
+ IS_IP6GRE_LINK_ASSERT(link);
+
+ HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_FWMARK);
+
+ *fwmark = ip6gre->fwmark;
+
+ return 0;
+}
+
+static void __init ip6gre_init(void)
+{
+ rtnl_link_register_info(&ip6gre_info_ops);
+}
+
+static void __exit ip6gre_exit(void)
+{
+ rtnl_link_unregister_info(&ip6gre_info_ops);
+}
diff --git a/lib/route/link/ip6tnl.c b/lib/route/link/ip6tnl.c
index 085bf66f..cdc90241 100644
--- a/lib/route/link/ip6tnl.c
+++ b/lib/route/link/ip6tnl.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/ip6tnl.c IP6TNL Link Info
- *
- * 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) 2014 Susant Sahani <susant@redhat.com>
*/
@@ -42,6 +36,7 @@
#define IP6_TNL_ATTR_FLAGS (1 << 6)
#define IP6_TNL_ATTR_PROTO (1 << 7)
#define IP6_TNL_ATTR_FLOWINFO (1 << 8)
+#define IP6_TNL_ATTR_FWMARK (1 << 9)
struct ip6_tnl_info
{
@@ -54,6 +49,7 @@ struct ip6_tnl_info
uint32_t flowinfo;
struct in6_addr local;
struct in6_addr remote;
+ uint32_t fwmark;
uint32_t ip6_tnl_mask;
};
@@ -67,6 +63,7 @@ static struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 },
[IFLA_IPTUN_FLAGS] = { .type = NLA_U32 },
[IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
+ [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
};
static int ip6_tnl_alloc(struct rtnl_link *link)
@@ -150,6 +147,11 @@ static int ip6_tnl_parse(struct rtnl_link *link, struct nlattr *data,
ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_PROTO;
}
+ if (tb[IFLA_IPTUN_FWMARK]) {
+ ip6_tnl->fwmark = nla_get_u32(tb[IFLA_IPTUN_FWMARK]);
+ ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FWMARK;
+ }
+
err = 0;
errout:
@@ -195,6 +197,9 @@ static int ip6_tnl_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
else
NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, 0);
+ if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK)
+ NLA_PUT_U32(msg, IFLA_IPTUN_FWMARK, ip6_tnl->fwmark);
+
nla_nest_end(msg, data);
nla_put_failure:
@@ -236,20 +241,14 @@ static void ip6_tnl_dump_details(struct rtnl_link *link, struct nl_dump_params *
if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LOCAL) {
nl_dump(p, " local ");
-
- if(inet_ntop(AF_INET6, &ip6_tnl->local, addr, INET6_ADDRSTRLEN))
- nl_dump_line(p, "%s\n", addr);
- else
- nl_dump_line(p, "%#x\n", ip6_tnl->local);
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &ip6_tnl->local, addr));
}
if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_REMOTE) {
nl_dump(p, " remote ");
-
- if(inet_ntop(AF_INET6, &ip6_tnl->remote, addr, INET6_ADDRSTRLEN))
- nl_dump_line(p, "%s\n", addr);
- else
- nl_dump_line(p, "%#x\n", ip6_tnl->remote);
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &ip6_tnl->remote, addr));
}
if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TTL) {
@@ -281,6 +280,11 @@ static void ip6_tnl_dump_details(struct rtnl_link *link, struct nl_dump_params *
nl_dump(p, " proto ");
nl_dump_line(p, " (%x)\n", ip6_tnl->proto);
}
+
+ if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK) {
+ nl_dump(p, " fwmark ");
+ nl_dump_line(p, "%x\n", ip6_tnl->fwmark);
+ }
}
static int ip6_tnl_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -688,6 +692,46 @@ uint8_t rtnl_link_ip6_tnl_get_proto(struct rtnl_link *link)
return ip6_tnl->proto;
}
+/**
+ * Set IP6_TNL tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6_tnl_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
+{
+ struct ip6_tnl_info *ip6_tnl = link->l_info;
+
+ IS_IP6_TNL_LINK_ASSERT(link);
+
+ ip6_tnl->fwmark = fwmark;
+ ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FWMARK;
+
+ return 0;
+}
+
+/**
+ * Get IP6_TNL tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark addr to fill in with the fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6_tnl_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
+{
+ struct ip6_tnl_info *ip6_tnl = link->l_info;
+
+ IS_IP6_TNL_LINK_ASSERT(link);
+
+ if (!(ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK))
+ return -NLE_NOATTR;
+
+ *fwmark = ip6_tnl->fwmark;
+
+ return 0;
+}
+
static void __init ip6_tnl_init(void)
{
rtnl_link_register_info(&ip6_tnl_info_ops);
diff --git a/lib/route/link/ip6vti.c b/lib/route/link/ip6vti.c
new file mode 100644
index 00000000..8c603abe
--- /dev/null
+++ b/lib/route/link/ip6vti.c
@@ -0,0 +1,554 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+
+/**
+ * @ingroup link
+ * @defgroup ip6vti IP6VTI
+ * ip6vti link module
+ *
+ * @details
+ * \b Link Type Name: "vti6"
+ *
+ * @route_doc{link_ip6vti, IP6VTI Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/ip6vti.h>
+#include <netlink-private/route/link/api.h>
+#include <linux/if_tunnel.h>
+
+#define IP6VTI_ATTR_LINK (1 << 0)
+#define IP6VTI_ATTR_IKEY (1 << 1)
+#define IP6VTI_ATTR_OKEY (1 << 2)
+#define IP6VTI_ATTR_LOCAL (1 << 3)
+#define IP6VTI_ATTR_REMOTE (1 << 4)
+#define IP6VTI_ATTR_FWMARK (1 << 5)
+
+struct ip6vti_info
+{
+ uint32_t link;
+ uint32_t ikey;
+ uint32_t okey;
+ struct in6_addr local;
+ struct in6_addr remote;
+ uint32_t fwmark;
+ uint32_t ip6vti_mask;
+};
+
+static struct nla_policy ip6vti_policy[IFLA_VTI_MAX + 1] = {
+ [IFLA_VTI_LINK] = { .type = NLA_U32 },
+ [IFLA_VTI_IKEY] = { .type = NLA_U32 },
+ [IFLA_VTI_OKEY] = { .type = NLA_U32 },
+ [IFLA_VTI_LOCAL] = { .minlen = sizeof(struct in6_addr) },
+ [IFLA_VTI_REMOTE] = { .minlen = sizeof(struct in6_addr) },
+ [IFLA_VTI_FWMARK] = { .type = NLA_U32 },
+};
+
+static int ip6vti_alloc(struct rtnl_link *link)
+{
+ struct ip6vti_info *ip6vti;
+
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*ip6vti));
+ else {
+ ip6vti = calloc(1, sizeof(*ip6vti));
+ if (!ip6vti)
+ return -NLE_NOMEM;
+
+ link->l_info = ip6vti;
+ }
+
+ return 0;
+}
+
+static int ip6vti_parse(struct rtnl_link *link, struct nlattr *data,
+ struct nlattr *xstats)
+{
+ struct nlattr *tb[IFLA_VTI_MAX + 1];
+ struct ip6vti_info *ip6vti;
+ int err;
+
+ NL_DBG(3, "Parsing IP6VTI link info\n");
+
+ err = nla_parse_nested(tb, IFLA_VTI_MAX, data, ip6vti_policy);
+ if (err < 0)
+ goto errout;
+
+ err = ip6vti_alloc(link);
+ if (err < 0)
+ goto errout;
+
+ ip6vti = link->l_info;
+
+ if (tb[IFLA_VTI_LINK]) {
+ ip6vti->link = nla_get_u32(tb[IFLA_VTI_LINK]);
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_LINK;
+ }
+
+ if (tb[IFLA_VTI_IKEY]) {
+ ip6vti->ikey = nla_get_u32(tb[IFLA_VTI_IKEY]);
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_IKEY;
+ }
+
+ if (tb[IFLA_VTI_OKEY]) {
+ ip6vti->okey = nla_get_u32(tb[IFLA_VTI_OKEY]);
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_OKEY;
+ }
+
+ if (tb[IFLA_VTI_LOCAL]) {
+ nla_memcpy(&ip6vti->local, tb[IFLA_VTI_LOCAL], sizeof(struct in6_addr));
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_LOCAL;
+ }
+
+ if (tb[IFLA_VTI_REMOTE]) {
+ nla_memcpy(&ip6vti->remote, tb[IFLA_VTI_REMOTE], sizeof(struct in6_addr));
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_REMOTE;
+ }
+
+ if (tb[IFLA_VTI_FWMARK]) {
+ ip6vti->fwmark = nla_get_u32(tb[IFLA_VTI_FWMARK]);
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
+ }
+
+ err = 0;
+
+ errout:
+ return err;
+}
+
+static int ip6vti_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+ struct nlattr *data;
+
+ data = nla_nest_start(msg, IFLA_INFO_DATA);
+ if (!data)
+ return -NLE_MSGSIZE;
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LINK)
+ NLA_PUT_U32(msg, IFLA_VTI_LINK, ip6vti->link);
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_IKEY)
+ NLA_PUT_U32(msg, IFLA_VTI_IKEY, ip6vti->ikey);
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_OKEY)
+ NLA_PUT_U32(msg, IFLA_VTI_OKEY, ip6vti->okey);
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LOCAL)
+ NLA_PUT(msg, IFLA_VTI_LOCAL, sizeof(struct in6_addr), &ip6vti->local);
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_REMOTE)
+ NLA_PUT(msg, IFLA_VTI_REMOTE, sizeof(struct in6_addr), &ip6vti->remote);
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK)
+ NLA_PUT_U32(msg, IFLA_VTI_FWMARK, ip6vti->fwmark);
+
+ nla_nest_end(msg, data);
+
+nla_put_failure:
+
+ return 0;
+}
+
+static void ip6vti_free(struct rtnl_link *link)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ free(ip6vti);
+ link->l_info = NULL;
+}
+
+static void ip6vti_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ nl_dump(p, "ip6vti : %s", link->l_name);
+}
+
+static void ip6vti_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+ char *name;
+ char addr[INET6_ADDRSTRLEN];
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LINK) {
+ nl_dump(p, " link ");
+ name = rtnl_link_get_name(link);
+ if (name)
+ nl_dump_line(p, "%s\n", name);
+ else
+ nl_dump_line(p, "%u\n", ip6vti->link);
+ }
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_IKEY) {
+ nl_dump(p, " ikey ");
+ nl_dump_line(p, "%x\n",ip6vti->ikey);
+ }
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_OKEY) {
+ nl_dump(p, " okey ");
+ nl_dump_line(p, "%x\n", ip6vti->okey);
+ }
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LOCAL) {
+ nl_dump(p, " local ");
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &ip6vti->local, addr));
+ }
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_REMOTE) {
+ nl_dump(p, " remote ");
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &ip6vti->remote, addr));
+ }
+
+ if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK) {
+ nl_dump(p, " fwmark ");
+ nl_dump_line(p, "%x\n", ip6vti->fwmark);
+ }
+}
+
+static int ip6vti_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct ip6vti_info *ip6vti_dst, *ip6vti_src = src->l_info;
+ int err;
+
+ dst->l_info = NULL;
+
+ err = rtnl_link_set_type(dst, "vti6");
+ if (err < 0)
+ return err;
+
+ ip6vti_dst = dst->l_info;
+
+ if (!ip6vti_dst || !ip6vti_src)
+ BUG();
+
+ memcpy(ip6vti_dst, ip6vti_src, sizeof(struct ip6vti_info));
+
+ return 0;
+}
+
+static struct rtnl_link_info_ops ip6vti_info_ops = {
+ .io_name = "vti6",
+ .io_alloc = ip6vti_alloc,
+ .io_parse = ip6vti_parse,
+ .io_dump = {
+ [NL_DUMP_LINE] = ip6vti_dump_line,
+ [NL_DUMP_DETAILS] = ip6vti_dump_details,
+ },
+ .io_clone = ip6vti_clone,
+ .io_put_attrs = ip6vti_put_attrs,
+ .io_free = ip6vti_free,
+};
+
+#define IS_IP6VTI_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &ip6vti_info_ops) { \
+ APPBUG("Link is not a ip6vti link. set type \"vti6\" first."); \
+ return -NLE_OPNOTSUPP; \
+ }
+
+#define HAS_IP6VTI_ATTR_ASSERT(ip6vti,attr) \
+ if (!((ip6vti)->ip6vti_mask & (attr))) \
+ return -NLE_NOATTR;
+
+struct rtnl_link *rtnl_link_ip6vti_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ link = rtnl_link_alloc();
+ if (!link)
+ return NULL;
+
+ err = rtnl_link_set_type(link, "vti6");
+ if (err < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Check if link is a IP6VTI link
+ * @arg link Link object
+ *
+ * @return True if link is a IP6VTI link, otherwise 0 is returned.
+ */
+int rtnl_link_is_ip6vti(struct rtnl_link *link)
+{
+ return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vti6");
+}
+/**
+ * Create a new vti6 tunnel device
+ * @arg sock netlink socket
+ * @arg name name of the tunnel deviceL
+ *
+ * Creates a new vti6 tunnel device in the kernel
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_add(struct nl_sock *sk, const char *name)
+{
+ struct rtnl_link *link;
+ int err;
+
+ link = rtnl_link_ip6vti_alloc();
+ if (!link)
+ return -NLE_NOMEM;
+
+ if(name)
+ rtnl_link_set_name(link, name);
+
+ err = rtnl_link_add(sk, link, NLM_F_CREATE);
+ rtnl_link_put(link);
+
+ return err;
+}
+/**
+ * Set IP6VTI tunnel interface index
+ * @arg link Link object
+ * @arg index interface index
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_set_link(struct rtnl_link *link, uint32_t index)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ ip6vti->link = index;
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_LINK;
+
+ return 0;
+}
+
+/**
+ * Get IP6VTI tunnel interface index
+ * @arg link Link object
+ * @arg index addr to fill in with the interface index
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_get_link(struct rtnl_link *link, uint32_t *index)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_LINK);
+
+ *index = ip6vti->link;
+
+ return 0;
+}
+
+/**
+ * Set IP6VTI tunnel set ikey
+ * @arg link Link object
+ * @arg ikey gre ikey
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_set_ikey(struct rtnl_link *link, uint32_t ikey)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ ip6vti->ikey = ikey;
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_IKEY;
+
+ return 0;
+}
+
+/**
+ * Get IP6VTI tunnel ikey
+ * @arg link Link object
+ * @arg ikey addr to fill in with the ikey
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_get_ikey(struct rtnl_link *link, uint32_t *ikey)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_IKEY);
+
+ *ikey = ip6vti->ikey;
+
+ return 0;
+}
+
+/**
+ * Set IP6VTI tunnel set okey
+ * @arg link Link object
+ * @arg okey gre okey
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_set_okey(struct rtnl_link *link, uint32_t okey)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ ip6vti->okey = okey;
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_OKEY;
+
+ return 0;
+}
+
+/**
+ * Get IP6VTI tunnel okey
+ * @arg link Link object
+ * @arg okey addr to fill in with the okey
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_get_okey(struct rtnl_link *link, uint32_t *okey)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_OKEY);
+
+ *okey = ip6vti->okey;
+
+ return 0;
+}
+
+/**
+ * Set IP6VTI tunnel local address
+ * @arg link Link object
+ * @arg local local address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_set_local(struct rtnl_link *link, struct in6_addr *local)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ memcpy(&ip6vti->local, local, sizeof(struct in6_addr));
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_LOCAL;
+
+ return 0;
+}
+
+/**
+ * Get IP6VTI tunnel local address
+ * @arg link Link object
+ * @arg local addr to fill in with remote address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_get_local(struct rtnl_link *link, struct in6_addr *local)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_LOCAL);
+
+ memcpy(local, &ip6vti->local, sizeof(struct in6_addr));
+
+ return 0;
+}
+
+/**
+ * Set IP6VTI tunnel remote address
+ * @arg link Link object
+ * @arg remote remote address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ memcpy(&ip6vti->remote, remote, sizeof(struct in6_addr));
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_REMOTE;
+
+ return 0;
+}
+
+/**
+ * Get IP6VTI tunnel remote address
+ * @arg link Link object
+ * @arg remote addr to fill in with remote address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_REMOTE);
+
+ memcpy(remote, &ip6vti->remote, sizeof(struct in6_addr));
+
+ return 0;
+}
+
+/**
+ * Set IP6VTI tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ ip6vti->fwmark = fwmark;
+ ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
+
+ return 0;
+}
+
+/**
+ * Get IP6VTI tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark addr to fill in with the fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
+{
+ struct ip6vti_info *ip6vti = link->l_info;
+
+ IS_IP6VTI_LINK_ASSERT(link);
+
+ HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_FWMARK);
+
+ *fwmark = ip6vti->fwmark;
+
+ return 0;
+}
+
+static void __init ip6vti_init(void)
+{
+ rtnl_link_register_info(&ip6vti_info_ops);
+}
+
+static void __exit ip6vti_exit(void)
+{
+ rtnl_link_unregister_info(&ip6vti_info_ops);
+}
diff --git a/lib/route/link/ipgre.c b/lib/route/link/ipgre.c
index a7665fef..f5a4998b 100644
--- a/lib/route/link/ipgre.c
+++ b/lib/route/link/ipgre.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/ipgre.c IPGRE Link Info
- *
- * 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) 2014 Susant Sahani <susant@redhat.com>
*/
@@ -42,6 +36,7 @@
#define IPGRE_ATTR_TTL (1 << 7)
#define IPGRE_ATTR_TOS (1 << 8)
#define IPGRE_ATTR_PMTUDISC (1 << 9)
+#define IPGRE_ATTR_FWMARK (1 << 10)
struct ipgre_info
{
@@ -55,6 +50,7 @@ struct ipgre_info
uint32_t link;
uint32_t local;
uint32_t remote;
+ uint32_t fwmark;
uint32_t ipgre_mask;
};
@@ -69,6 +65,7 @@ static struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
[IFLA_GRE_TTL] = { .type = NLA_U8 },
[IFLA_GRE_TOS] = { .type = NLA_U8 },
[IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
+ [IFLA_GRE_FWMARK] = { .type = NLA_U32 },
};
static int ipgre_alloc(struct rtnl_link *link)
@@ -157,6 +154,11 @@ static int ipgre_parse(struct rtnl_link *link, struct nlattr *data,
ipgre->ipgre_mask |= IPGRE_ATTR_PMTUDISC;
}
+ if (tb[IFLA_GRE_FWMARK]) {
+ ipgre->fwmark = nla_get_u32(tb[IFLA_GRE_FWMARK]);
+ ipgre->ipgre_mask |= IPGRE_ATTR_FWMARK;
+ }
+
err = 0;
errout:
@@ -202,6 +204,9 @@ static int ipgre_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
if (ipgre->ipgre_mask & IPGRE_ATTR_PMTUDISC)
NLA_PUT_U8(msg, IFLA_GRE_PMTUDISC, ipgre->pmtudisc);
+ if (ipgre->ipgre_mask & IPGRE_ATTR_FWMARK)
+ NLA_PUT_U32(msg, IFLA_GRE_FWMARK, ipgre->fwmark);
+
nla_nest_end(msg, data);
nla_put_failure:
@@ -292,6 +297,11 @@ static void ipgre_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump(p, " pmtudisc ");
nl_dump_line(p, "enabled (%#x)\n", ipgre->pmtudisc);
}
+
+ if (ipgre->ipgre_mask & IPGRE_ATTR_FWMARK) {
+ nl_dump(p, " fwmark ");
+ nl_dump_line(p, "%x\n", ipgre->fwmark);
+ }
}
static int ipgre_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -829,6 +839,46 @@ uint8_t rtnl_link_get_pmtudisc(struct rtnl_link *link)
return rtnl_link_ipgre_get_pmtudisc (link);
}
+/**
+ * Set IPGRE tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipgre_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
+{
+ struct ipgre_info *ipgre = link->l_info;
+
+ IS_IPGRE_LINK_ASSERT(link);
+
+ ipgre->fwmark = fwmark;
+ ipgre->ipgre_mask |= IPGRE_ATTR_FWMARK;
+
+ return 0;
+}
+
+/**
+ * Get IPGRE tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark addr to fill in with the fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipgre_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
+{
+ struct ipgre_info *ipgre = link->l_info;
+
+ IS_IPGRE_LINK_ASSERT(link);
+
+ if (!(ipgre->ipgre_mask & IPGRE_ATTR_FWMARK))
+ return -NLE_NOATTR;
+
+ *fwmark = ipgre->fwmark;
+
+ return 0;
+}
+
static void __init ipgre_init(void)
{
rtnl_link_register_info(&ipgre_info_ops);
diff --git a/lib/route/link/ipip.c b/lib/route/link/ipip.c
index 3243b56b..e905ef99 100644
--- a/lib/route/link/ipip.c
+++ b/lib/route/link/ipip.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/ipip.c IPIP Link Info
- *
- * 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) 2014 Susant Sahani <susant@redhat.com>
*/
@@ -38,6 +32,7 @@
#define IPIP_ATTR_TTL (1 << 3)
#define IPIP_ATTR_TOS (1 << 4)
#define IPIP_ATTR_PMTUDISC (1 << 5)
+#define IPIP_ATTR_FWMARK (1 << 6)
struct ipip_info
{
@@ -47,6 +42,7 @@ struct ipip_info
uint32_t link;
uint32_t local;
uint32_t remote;
+ uint32_t fwmark;
uint32_t ipip_mask;
};
@@ -57,6 +53,7 @@ static struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_TTL] = { .type = NLA_U8 },
[IFLA_IPTUN_TOS] = { .type = NLA_U8 },
[IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
+ [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
};
static int ipip_alloc(struct rtnl_link *link)
@@ -125,6 +122,11 @@ static int ipip_parse(struct rtnl_link *link, struct nlattr *data,
ipip->ipip_mask |= IPIP_ATTR_PMTUDISC;
}
+ if (tb[IFLA_IPTUN_FWMARK]) {
+ ipip->fwmark = nla_get_u32(tb[IFLA_IPTUN_FWMARK]);
+ ipip->ipip_mask |= IPIP_ATTR_FWMARK;
+ }
+
err = 0;
errout:
@@ -158,6 +160,9 @@ static int ipip_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
if (ipip->ipip_mask & IPIP_ATTR_PMTUDISC)
NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, ipip->pmtudisc);
+ if (ipip->ipip_mask & IPIP_ATTR_FWMARK)
+ NLA_PUT_U32(msg, IFLA_IPTUN_FWMARK, ipip->fwmark);
+
nla_nest_end(msg, data);
nla_put_failure:
@@ -227,6 +232,11 @@ static void ipip_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump(p, " pmtudisc ");
nl_dump_line(p, "enabled (%#x)\n", ipip->pmtudisc);
}
+
+ if (ipip->ipip_mask & IPIP_ATTR_FWMARK) {
+ nl_dump(p, " fwmark ");
+ nl_dump_line(p, "%x\n", ipip->fwmark);
+ }
}
static int ipip_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -528,6 +538,46 @@ uint8_t rtnl_link_ipip_get_pmtudisc(struct rtnl_link *link)
return ipip->pmtudisc;
}
+/**
+ * Set IPIP tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipip_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
+{
+ struct ipip_info *ipip = link->l_info;
+
+ IS_IPIP_LINK_ASSERT(link);
+
+ ipip->fwmark = fwmark;
+ ipip->ipip_mask |= IPIP_ATTR_FWMARK;
+
+ return 0;
+}
+
+/**
+ * Get IPIP tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark addr to fill in with the fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipip_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
+{
+ struct ipip_info *ipip = link->l_info;
+
+ IS_IPIP_LINK_ASSERT(link);
+
+ if (!(ipip->ipip_mask & IPIP_ATTR_FWMARK))
+ return -NLE_NOATTR;
+
+ *fwmark = ipip->fwmark;
+
+ return 0;
+}
+
static void __init ipip_init(void)
{
rtnl_link_register_info(&ipip_info_ops);
diff --git a/lib/route/link/ipvlan.c b/lib/route/link/ipvlan.c
index 84ace435..020f2cb9 100644
--- a/lib/route/link/ipvlan.c
+++ b/lib/route/link/ipvlan.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/ipvlan.c IPVLAN Link Info
- *
- * 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) 2015 Cong Wang <cwang@twopensource.com>
*/
@@ -178,12 +172,11 @@ static struct rtnl_link_info_ops ipvlan_info_ops = {
struct rtnl_link *rtnl_link_ipvlan_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "ipvlan")) < 0) {
+ if (rtnl_link_set_type(link, "ipvlan") < 0) {
rtnl_link_put(link);
return NULL;
}
diff --git a/lib/route/link/ipvti.c b/lib/route/link/ipvti.c
index 851d5665..9f9d3d68 100644
--- a/lib/route/link/ipvti.c
+++ b/lib/route/link/ipvti.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/ipvti.c IPVTI Link Info
- *
- * 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) 2014 Susant Sahani <susant@redhat.com>
*/
@@ -37,6 +31,7 @@
#define IPVTI_ATTR_OKEY (1 << 2)
#define IPVTI_ATTR_LOCAL (1 << 3)
#define IPVTI_ATTR_REMOTE (1 << 4)
+#define IPVTI_ATTR_FWMARK (1 << 5)
struct ipvti_info
{
@@ -45,6 +40,7 @@ struct ipvti_info
uint32_t okey;
uint32_t local;
uint32_t remote;
+ uint32_t fwmark;
uint32_t ipvti_mask;
};
@@ -54,6 +50,7 @@ static struct nla_policy ipvti_policy[IFLA_VTI_MAX + 1] = {
[IFLA_VTI_OKEY] = { .type = NLA_U32 },
[IFLA_VTI_LOCAL] = { .type = NLA_U32 },
[IFLA_VTI_REMOTE] = { .type = NLA_U32 },
+ [IFLA_VTI_FWMARK] = { .type = NLA_U32 },
};
static int ipvti_alloc(struct rtnl_link *link)
@@ -117,6 +114,11 @@ static int ipvti_parse(struct rtnl_link *link, struct nlattr *data,
ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE;
}
+ if (tb[IFLA_VTI_FWMARK]) {
+ ipvti->fwmark = nla_get_u32(tb[IFLA_VTI_FWMARK]);
+ ipvti->ipvti_mask |= IPVTI_ATTR_FWMARK;
+ }
+
err = 0;
errout:
@@ -147,6 +149,9 @@ static int ipvti_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE)
NLA_PUT_U32(msg, IFLA_VTI_REMOTE, ipvti->remote);
+ if (ipvti->ipvti_mask & IPVTI_ATTR_FWMARK)
+ NLA_PUT_U32(msg, IFLA_VTI_FWMARK, ipvti->fwmark);
+
nla_nest_end(msg, data);
nla_put_failure:
@@ -212,6 +217,11 @@ static void ipvti_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
else
nl_dump_line(p, "%#x\n", ntohs(ipvti->remote));
}
+
+ if (ipvti->ipvti_mask & IPVTI_ATTR_FWMARK) {
+ nl_dump(p, " fwmark ");
+ nl_dump_line(p, "%x\n", ipvti->fwmark);
+ }
}
static int ipvti_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -477,6 +487,46 @@ uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link)
return ipvti->remote;
}
+/**
+ * Set IPVTI tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipvti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
+{
+ struct ipvti_info *ipvti = link->l_info;
+
+ IS_IPVTI_LINK_ASSERT(link);
+
+ ipvti->fwmark = fwmark;
+ ipvti->ipvti_mask |= IPVTI_ATTR_FWMARK;
+
+ return 0;
+}
+
+/**
+ * Get IPVTI tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark addr to fill in with the fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipvti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
+{
+ struct ipvti_info *ipvti = link->l_info;
+
+ IS_IPVTI_LINK_ASSERT(link);
+
+ if (!(ipvti->ipvti_mask & IPVTI_ATTR_FWMARK))
+ return -NLE_NOATTR;
+
+ *fwmark = ipvti->fwmark;
+
+ return 0;
+}
+
static void __init ipvti_init(void)
{
rtnl_link_register_info(&ipvti_info_ops);
diff --git a/lib/route/link/macsec.c b/lib/route/link/macsec.c
index fa115e27..16b65b04 100644
--- a/lib/route/link/macsec.c
+++ b/lib/route/link/macsec.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/macsec.c MACsec Link Info
- *
- * 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) 2016 Sabrina Dubroca <sd@queasysnail.net>
*/
@@ -47,6 +41,7 @@
#define MACSEC_ATTR_REPLAY_PROTECT (1 << 10)
#define MACSEC_ATTR_VALIDATION (1 << 11)
#define MACSEC_ATTR_PORT (1 << 12)
+#define MACSEC_ATTR_OFFLOAD (1 << 13)
struct macsec_info {
int ifindex;
@@ -58,7 +53,7 @@ struct macsec_info {
enum macsec_validation_type validate;
uint8_t encoding_sa;
- uint8_t send_sci, end_station, scb, replay_protect, protect, encrypt;
+ uint8_t send_sci, end_station, scb, replay_protect, protect, encrypt, offload;
uint32_t ce_mask;
};
@@ -80,6 +75,7 @@ static struct nla_policy macsec_policy[IFLA_MACSEC_MAX+1] = {
[IFLA_MACSEC_SCB] = { .type = NLA_U8 },
[IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 },
[IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 },
+ [IFLA_MACSEC_OFFLOAD] = { .type = NLA_U8 },
};
/**
@@ -164,6 +160,11 @@ static int macsec_parse(struct rtnl_link *link, struct nlattr *data,
info->ce_mask |= MACSEC_ATTR_ENCRYPT;
}
+ if (tb[IFLA_MACSEC_OFFLOAD]) {
+ info->offload = nla_get_u8(tb[IFLA_MACSEC_OFFLOAD]);
+ info->ce_mask |= MACSEC_ATTR_OFFLOAD;
+ }
+
if (tb[IFLA_MACSEC_INC_SCI]) {
info->send_sci = nla_get_u8(tb[IFLA_MACSEC_INC_SCI]);
info->ce_mask |= MACSEC_ATTR_INC_SCI;
@@ -262,7 +263,8 @@ static void macsec_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
struct macsec_info *info = link->l_info;
char tmp[128];
- nl_dump(p, "sci %016llx <%s>", ntohll(info->sci), flags_str(tmp, sizeof(tmp), info));
+ nl_dump(p, "sci %016llx <%s>", (long long unsigned)ntohll(info->sci),
+ flags_str(tmp, sizeof(tmp), info));
}
static void macsec_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
@@ -270,12 +272,15 @@ static void macsec_dump_details(struct rtnl_link *link, struct nl_dump_params *p
struct macsec_info *info = link->l_info;
char tmp[128];
- nl_dump(p, " sci %016llx protect %s encoding_sa %d encrypt %s send_sci %s validate %s %s\n",
- ntohll(info->sci), values_on_off[info->protect], info->encoding_sa, values_on_off[info->encrypt], values_on_off[info->send_sci],
+ nl_dump(p,
+ " sci %016llx protect %s encoding_sa %d encrypt %s send_sci %s validate %s %s\n",
+ (long long unsigned)ntohll(info->sci),
+ values_on_off[info->protect], info->encoding_sa,
+ values_on_off[info->encrypt], values_on_off[info->send_sci],
VALIDATE_STR[info->validate],
replay_protect_str(tmp, info->replay_protect, info->window));
nl_dump(p, " cipher suite: %016llx, icv_len %d\n",
- info->cipher_suite, info->icv_len);
+ (long long unsigned)info->cipher_suite, info->icv_len);
}
static int macsec_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -312,6 +317,9 @@ static int macsec_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
if ((info->ce_mask & MACSEC_ATTR_ENCRYPT))
NLA_PUT_U8(msg, IFLA_MACSEC_ENCRYPT, info->encrypt);
+ if ((info->ce_mask & MACSEC_ATTR_OFFLOAD))
+ NLA_PUT_U8(msg, IFLA_MACSEC_OFFLOAD, info->offload);
+
if (info->cipher_suite != MACSEC_DEFAULT_CIPHER_ID || info->icv_len != DEFAULT_ICV_LEN) {
NLA_PUT_U64(msg, IFLA_MACSEC_CIPHER_SUITE, info->cipher_suite);
NLA_PUT_U8(msg, IFLA_MACSEC_ICV_LEN, info->icv_len);
@@ -638,6 +646,36 @@ int rtnl_link_macsec_get_encrypt(struct rtnl_link *link, uint8_t *encrypt)
return 0;
}
+int rtnl_link_macsec_set_offload(struct rtnl_link *link, uint8_t offload)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (offload > 1)
+ return -NLE_INVAL;
+
+ info->offload = offload;
+ info->ce_mask |= MACSEC_ATTR_OFFLOAD;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_offload(struct rtnl_link *link, uint8_t *offload)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_OFFLOAD))
+ return -NLE_NOATTR;
+
+ if (offload)
+ *offload = info->offload;
+
+ return 0;
+}
+
int rtnl_link_macsec_set_encoding_sa(struct rtnl_link *link, uint8_t encoding_sa)
{
struct macsec_info *info = link->l_info;
@@ -674,7 +712,7 @@ int rtnl_link_macsec_set_validation_type(struct rtnl_link *link, enum macsec_val
IS_MACSEC_LINK_ASSERT(link);
- if (validate > 1)
+ if (validate > MACSEC_VALIDATE_MAX)
return -NLE_INVAL;
info->validate = validate;
diff --git a/lib/route/link/macvlan.c b/lib/route/link/macvlan.c
index a23fe6d8..df61bb20 100644
--- a/lib/route/link/macvlan.c
+++ b/lib/route/link/macvlan.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/macvlan.c MACVLAN Link Info
- *
- * 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) 2013 Michael Braun <michael-dev@fami-braun.de>
*/
@@ -123,6 +117,10 @@ static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
mvi->mvi_macaddr = calloc(mvi->mvi_maccount,
sizeof(*(mvi->mvi_macaddr)));
+ if (mvi->mvi_macaddr == NULL) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
i = 0;
for (; nla_ok(nla, len); nla = nla_next(nla, &len)) {
@@ -149,6 +147,8 @@ static void macvlan_free(struct rtnl_link *link)
uint32_t i;
mvi = link->l_info;
+ if (!mvi)
+ return;
for (i = 0; i < mvi->mvi_maccount; i++)
nl_addr_put(mvi->mvi_macaddr[i]);
@@ -307,12 +307,11 @@ static struct rtnl_link_info_ops macvtap_info_ops = {
struct rtnl_link *rtnl_link_macvlan_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "macvlan")) < 0) {
+ if (rtnl_link_set_type(link, "macvlan") < 0) {
rtnl_link_put(link);
return NULL;
}
@@ -653,12 +652,11 @@ int rtnl_link_macvlan_del_macaddr(struct rtnl_link *link, struct nl_addr *addr)
struct rtnl_link *rtnl_link_macvtap_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "macvtap")) < 0) {
+ if (rtnl_link_set_type(link, "macvtap") < 0) {
rtnl_link_put(link);
return NULL;
}
diff --git a/lib/route/link/ppp.c b/lib/route/link/ppp.c
index b05e7f3f..a5fb400d 100644
--- a/lib/route/link/ppp.c
+++ b/lib/route/link/ppp.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/ppp.c PPP Link Module
- *
- * 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) 2016 Jonas Johansson <jonasj76@gmail.com>
*/
@@ -156,12 +150,11 @@ static struct rtnl_link_info_ops ppp_info_ops = {
struct rtnl_link *rtnl_link_ppp_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "ppp")) < 0) {
+ if (rtnl_link_set_type(link, "ppp") < 0) {
rtnl_link_put(link);
return NULL;
}
diff --git a/lib/route/link/sit.c b/lib/route/link/sit.c
index 88565137..fabb811f 100644
--- a/lib/route/link/sit.c
+++ b/lib/route/link/sit.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/sit.c SIT Link Info
- *
- * 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) 2014 Susant Sahani <susant@redhat.com>
*/
@@ -44,6 +38,7 @@
#define SIT_ATTR_6RD_RELAY_PREFIX (1 << 9)
#define SIT_ATTR_6RD_PREFIXLEN (1 << 10)
#define SIT_ATTR_6RD_RELAY_PREFIXLEN (1 << 11)
+#define SIT_ATTR_FWMARK (1 << 12)
struct sit_info
{
@@ -59,6 +54,7 @@ struct sit_info
uint32_t ip6rd_relay_prefix;
uint16_t ip6rd_prefixlen;
uint16_t ip6rd_relay_prefixlen;
+ uint32_t fwmark;
uint32_t sit_mask;
};
@@ -75,6 +71,7 @@ static struct nla_policy sit_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 },
[IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 },
[IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
+ [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
};
static int sit_alloc(struct rtnl_link *link)
@@ -174,6 +171,11 @@ static int sit_parse(struct rtnl_link *link, struct nlattr *data,
sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIXLEN;
}
+ if (tb[IFLA_IPTUN_FWMARK]) {
+ sit->fwmark = nla_get_u32(tb[IFLA_IPTUN_FWMARK]);
+ sit->sit_mask |= SIT_ATTR_FWMARK;
+ }
+
err = 0;
errout:
@@ -225,6 +227,9 @@ static int sit_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIXLEN)
NLA_PUT_U16(msg, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, sit->ip6rd_relay_prefixlen);
+ if (sit->sit_mask & SIT_ATTR_FWMARK)
+ NLA_PUT_U32(msg, IFLA_IPTUN_FWMARK, sit->fwmark);
+
nla_nest_end(msg, data);
nla_put_failure:
@@ -326,6 +331,11 @@ static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump(p, " 6rd_relay_prefixlen ");
nl_dump_line(p, "%d\n", sit->ip6rd_relay_prefixlen);
}
+
+ if (sit->sit_mask & SIT_ATTR_FWMARK) {
+ nl_dump(p, " fwmark ");
+ nl_dump_line(p, "%x\n", sit->fwmark);
+ }
}
static int sit_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -812,6 +822,42 @@ int rtnl_link_sit_get_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t *pr
return 0;
}
+/**
+ * Set SIT tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_sit_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ sit->fwmark = fwmark;
+ sit->sit_mask |= SIT_ATTR_FWMARK;
+
+ return 0;
+}
+
+/**
+ * Get SIT tunnel fwmark
+ * @arg link Link object
+ * @arg fwmark addr to fill in with the fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_sit_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ if (!(sit->sit_mask & SIT_ATTR_FWMARK))
+ return -NLE_NOATTR;
+
+ *fwmark = sit->fwmark;
+
+ return 0;
+}
+
static void __init sit_init(void)
{
rtnl_link_register_info(&sit_info_ops);
diff --git a/lib/route/link/sriov.c b/lib/route/link/sriov.c
index 2a87cfe5..3a728147 100644
--- a/lib/route/link/sriov.c
+++ b/lib/route/link/sriov.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/sriov.c SRIOV VF Info
- *
- * 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) 2016 Intel Corp. All rights reserved.
* Copyright (c) 2016 Jef Oliver <jef.oliver@intel.com>
*/
@@ -92,7 +86,7 @@ int rtnl_link_sriov_clone(struct rtnl_link *dst, struct rtnl_link *src) {
nl_vf_vlans_t *src_vlans = NULL, *dst_vlans = NULL;
nl_vf_vlan_info_t *src_vlan_info = NULL, *dst_vlan_info = NULL;
- if (!(err = rtnl_link_has_vf_list(src)))
+ if (!rtnl_link_has_vf_list(src))
return 0;
dst->l_vf_list = rtnl_link_vf_alloc();
@@ -129,7 +123,7 @@ int rtnl_link_sriov_clone(struct rtnl_link *dst, struct rtnl_link *src) {
dst_vlan_info = dst_vlans->vlans;
memcpy(dst_vlans, src_vlans, sizeof(nl_vf_vlans_t));
memcpy(dst_vlan_info, src_vlan_info,
- dst_vlans->size * sizeof(dst_vlan_info));
+ dst_vlans->size * sizeof(*dst_vlan_info));
d_vf->vf_vlans = dst_vlans;
}
@@ -213,10 +207,9 @@ static void dump_vf_details(struct rtnl_link_vf *vf_data,
/* Loop through SRIOV VF list dump details */
void rtnl_link_sriov_dump_details(struct rtnl_link *link,
struct nl_dump_params *p) {
- int err;
struct rtnl_link_vf *vf_data, *list, *next;
- if (!(err = rtnl_link_has_vf_list(link)))
+ if (!rtnl_link_has_vf_list(link))
BUG();
nl_dump(p, " SRIOV VF List\n");
@@ -235,7 +228,7 @@ static void dump_vf_stats(struct rtnl_link_vf *vf_data,
char *unit;
float res;
- nl_dump(p, " VF %" PRIu64 " Stats:\n", vf_data->vf_index);
+ nl_dump(p, " VF %u Stats:\n", vf_data->vf_index);
nl_dump_line(p, "\tRX: %-14s %-10s %-10s %-10s\n",
"bytes", "packets", "multicast", "broadcast");
@@ -277,10 +270,9 @@ void rtnl_link_sriov_dump_stats(struct rtnl_link *link,
/* Free stored SRIOV VF data */
void rtnl_link_sriov_free_data(struct rtnl_link *link) {
- int err = 0;
struct rtnl_link_vf *list, *vf, *next;
- if (!(err = rtnl_link_has_vf_list(link)))
+ if (!rtnl_link_has_vf_list(link))
return;
list = link->l_vf_list;
@@ -656,7 +648,7 @@ int rtnl_link_sriov_parse_vflist(struct rtnl_link *link, struct nlattr **tb) {
}
if (t[IFLA_VF_STATS]) {
- err = nla_parse_nested(stb, IFLA_VF_STATS_MAX,
+ err = nla_parse_nested(stb, RTNL_LINK_VF_STATS_MAX,
t[IFLA_VF_STATS],
sriov_stats_policy);
if (err < 0) {
@@ -683,7 +675,7 @@ int rtnl_link_sriov_parse_vflist(struct rtnl_link *link, struct nlattr **tb) {
RTNL_LINK_VF_STATS_MULTICAST,
IFLA_VF_STATS_MULTICAST);
- vf_data->ce_mask |= IFLA_VF_STATS;
+ vf_data->ce_mask |= SRIOV_ATTR_STATS;
}
if (t[IFLA_VF_TRUST]) {
diff --git a/lib/route/link/team.c b/lib/route/link/team.c
new file mode 100644
index 00000000..1bcc86ed
--- /dev/null
+++ b/lib/route/link/team.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Copyright (c) 2015 Jonas Johansson <jonasj76@gmail.com>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup team Team
+ *
+ * @details
+ * \b Link Type Name: "team"
+ *
+ * @route_doc{link_team, Team Documentation}
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/route/link/team.h>
+
+/**
+ * Allocate link object of type team
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_team_alloc(void)
+{
+ struct rtnl_link *link;
+
+ if (!(link = rtnl_link_alloc()))
+ return NULL;
+
+ if (rtnl_link_set_type(link, "team") < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Create a new kernel team device
+ * @arg sock netlink socket
+ * @arg name name of team device or NULL
+ * @arg opts team options (currently unused)
+ *
+ * Creates a new team device in the kernel. If no name is
+ * provided, the kernel will automatically pick a name of the
+ * form "type%d" (e.g. team0, vlan1, etc.)
+ *
+ * The \a opts argument is currently unused. In the future, it
+ * may be used to carry additional team options to be set
+ * when creating the team device.
+ *
+ * @note When letting the kernel assign a name, it will become
+ * difficult to retrieve the interface afterwards because
+ * you have to guess the name the kernel has chosen. It is
+ * therefore not recommended to not provide a device name.
+ *
+ * @see rtnl_link_team_enslave()
+ * @see rtnl_link_team_release()
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_team_add(struct nl_sock *sock, const char *name,
+ struct rtnl_link *opts)
+{
+ struct rtnl_link *link;
+ int err;
+
+ if (!(link = rtnl_link_team_alloc()))
+ return -NLE_NOMEM;
+
+ if (!name && opts)
+ name = rtnl_link_get_name(opts);
+
+ if (name)
+ rtnl_link_set_name(link, name);
+
+ err = rtnl_link_add(sock, link, NLM_F_CREATE);
+
+ rtnl_link_put(link);
+
+ return err;
+}
+
+static struct rtnl_link_info_ops team_info_ops = {
+ .io_name = "team",
+};
+
+static void __init team_init(void)
+{
+ rtnl_link_register_info(&team_info_ops);
+}
+
+static void __exit team_exit(void)
+{
+ rtnl_link_unregister_info(&team_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/veth.c b/lib/route/link/veth.c
index 15859de8..37f43f69 100644
--- a/lib/route/link/veth.c
+++ b/lib/route/link/veth.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/veth.c Virtual Ethernet
- *
- * 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) 2013 Cong Wang <xiyou.wangcong@gmail.com>
*/
@@ -213,11 +207,10 @@ static struct rtnl_link_info_ops veth_info_ops = {
struct rtnl_link *rtnl_link_veth_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "veth")) < 0) {
+ if (rtnl_link_set_type(link, "veth") < 0) {
rtnl_link_put(link);
return NULL;
}
diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c
index 7c5aa069..36f88225 100644
--- a/lib/route/link/vlan.c
+++ b/lib/route/link/vlan.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/vlan.c VLAN Link Info
- *
- * 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>
*/
@@ -392,12 +386,11 @@ static struct rtnl_link_info_ops vlan_info_ops = {
struct rtnl_link *rtnl_link_vlan_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "vlan")) < 0) {
+ if (rtnl_link_set_type(link, "vlan") < 0) {
rtnl_link_put(link);
return NULL;
}
@@ -647,6 +640,7 @@ static const struct trans_tbl vlan_flags[] = {
__ADD(VLAN_FLAG_GVRP, gvrp),
__ADD(VLAN_FLAG_LOOSE_BINDING, loose_binding),
__ADD(VLAN_FLAG_MVRP, mvrp),
+ __ADD(VLAN_FLAG_BRIDGE_BINDING, bridge_binding),
};
/**
diff --git a/lib/route/link/vrf.c b/lib/route/link/vrf.c
index 8b6b451f..c4edd3ef 100644
--- a/lib/route/link/vrf.c
+++ b/lib/route/link/vrf.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/vrf.c VRF Link Info
- *
- * 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) 2015 Cumulus Networks. All rights reserved.
* Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
*/
@@ -181,12 +175,11 @@ static struct rtnl_link_info_ops vrf_info_ops = {
struct rtnl_link *rtnl_link_vrf_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "vrf")) < 0) {
+ if (rtnl_link_set_type(link, "vrf") < 0) {
rtnl_link_put(link);
return NULL;
}
@@ -240,8 +233,8 @@ int rtnl_link_vrf_set_tableid(struct rtnl_link *link, uint32_t id)
struct vrf_info *vi = link->l_info;
IS_VRF_LINK_ASSERT(link);
- if(id > VRF_TABLE_ID_MAX)
- return -NLE_INVAL;
+
+ _NL_STATIC_ASSERT(VRF_TABLE_ID_MAX == UINT32_MAX);
vi->table_id = id;
vi->vi_mask |= VRF_HAS_TABLE_ID;
diff --git a/lib/route/link/vxlan.c b/lib/route/link/vxlan.c
index 686ac31e..7b8429c8 100644
--- a/lib/route/link/vxlan.c
+++ b/lib/route/link/vxlan.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/vxlan.c VXLAN Link Info
- *
- * 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) 2013 Yasunobu Chiba <yasu@dsl.gr.jp>
*/
@@ -322,16 +316,12 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
if (vxi->ce_mask & VXLAN_ATTR_GROUP) {
nl_dump(p, " group ");
- if (inet_ntop(AF_INET, &vxi->vxi_group, addr, sizeof(addr)))
- nl_dump_line(p, "%s\n", addr);
- else
- nl_dump_line(p, "%#x\n", ntohs(vxi->vxi_group));
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET, &vxi->vxi_group, addr));
} else if (vxi->ce_mask & VXLAN_ATTR_GROUP6) {
nl_dump(p, " group ");
- if (inet_ntop(AF_INET6, &vxi->vxi_group6, addr, sizeof(addr)))
- nl_dump_line(p, "%s\n", addr);
- else
- nl_dump_line(p, "%#x\n", vxi->vxi_group6);
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &vxi->vxi_group6, addr));
}
if (vxi->ce_mask & VXLAN_ATTR_LINK) {
@@ -350,19 +340,14 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
if (vxi->ce_mask & VXLAN_ATTR_LOCAL) {
nl_dump(p, " local ");
- if (inet_ntop(AF_INET, &vxi->vxi_local, addr, sizeof(addr)))
- nl_dump_line(p, "%s\n", addr);
- else
- nl_dump_line(p, "%#x\n", ntohs(vxi->vxi_local));
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET, &vxi->vxi_local, addr));
} else if (vxi->ce_mask & VXLAN_ATTR_LOCAL6) {
nl_dump(p, " local ");
- if (inet_ntop(AF_INET6, &vxi->vxi_local6, addr, sizeof(addr)))
- nl_dump_line(p, "%s\n", addr);
- else
- nl_dump_line(p, "%#x\n", vxi->vxi_local6);
+ nl_dump_line(p, "%s\n",
+ _nl_inet_ntop(AF_INET6, &vxi->vxi_local6, addr));
}
-
if (vxi->ce_mask & VXLAN_ATTR_TTL) {
nl_dump(p, " ttl ");
if(vxi->vxi_ttl)
@@ -374,7 +359,7 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
if (vxi->ce_mask & VXLAN_ATTR_TOS) {
nl_dump(p, " tos ");
if (vxi->vxi_tos == 1)
- nl_dump_line(p, "inherit\n", vxi->vxi_tos);
+ nl_dump_line(p, "inherit\n");
else
nl_dump_line(p, "%#x\n", vxi->vxi_tos);
}
@@ -701,12 +686,11 @@ static struct rtnl_link_info_ops vxlan_info_ops = {
struct rtnl_link *rtnl_link_vxlan_alloc(void)
{
struct rtnl_link *link;
- int err;
if (!(link = rtnl_link_alloc()))
return NULL;
- if ((err = rtnl_link_set_type(link, "vxlan")) < 0) {
+ if (rtnl_link_set_type(link, "vxlan") < 0) {
rtnl_link_put(link);
return NULL;
}
diff --git a/lib/route/link/xfrmi.c b/lib/route/link/xfrmi.c
index 5a4a5630..92531f24 100644
--- a/lib/route/link/xfrmi.c
+++ b/lib/route/link/xfrmi.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/link/xfrmi.c XFRMI Link Info
- *
- * 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) 2019 Eyal Birger <eyal.birger@gmail.com>
*
* Based on lib/route/link/ipvti.c
diff --git a/lib/route/mdb.c b/lib/route/mdb.c
new file mode 100644
index 00000000..459959ee
--- /dev/null
+++ b/lib/route/mdb.c
@@ -0,0 +1,466 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * lib/route/mdb.c Multicast Database
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/route/mdb.h>
+#include <netlink/utils.h>
+#include <linux/if_bridge.h>
+
+/** @cond SKIP */
+#define MDB_ATTR_IFINDEX 0x000001
+#define MDB_ATTR_ENTRIES 0x000002
+
+static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(void);
+static void rtnl_mdb_entry_free(struct rtnl_mdb_entry *mdb_entry);
+
+static struct nl_cache_ops rtnl_mdb_ops;
+static struct nl_object_ops mdb_obj_ops;
+/** @endcond */
+
+static void mdb_constructor(struct nl_object *obj)
+{
+ struct rtnl_mdb *_mdb = (struct rtnl_mdb *) obj;
+
+ nl_init_list_head(&_mdb->mdb_entry_list);
+}
+
+static void mdb_free_data(struct nl_object *obj)
+{
+ struct rtnl_mdb *mdb = (struct rtnl_mdb *)obj;
+ struct rtnl_mdb_entry *mdb_entry;
+ struct rtnl_mdb_entry *mdb_entry_safe;
+
+ nl_list_for_each_entry_safe(mdb_entry, mdb_entry_safe,
+ &mdb->mdb_entry_list, mdb_list)
+ rtnl_mdb_entry_free(mdb_entry);
+}
+
+static int mdb_entry_equal(struct rtnl_mdb_entry *a, struct rtnl_mdb_entry *b)
+{
+ return a->ifindex == b->ifindex
+ && a->vid == b->vid
+ && a->proto == b->proto
+ && a->state == b->state
+ && nl_addr_cmp(a->addr, b->addr) == 0;
+}
+
+static uint64_t mdb_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
+{
+ struct rtnl_mdb *a = (struct rtnl_mdb *) _a;
+ struct rtnl_mdb *b = (struct rtnl_mdb *) _b;
+ struct rtnl_mdb_entry *a_entry, *b_entry;
+ uint64_t diff = 0;
+
+#define MDB_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MDB_ATTR_##ATTR, a, b, EXPR)
+ diff |= MDB_DIFF(IFINDEX, a->ifindex != b->ifindex);
+#undef MDB_DIFF
+
+ a_entry = nl_list_entry(a->mdb_entry_list.next, struct rtnl_mdb_entry, mdb_list);
+ b_entry = nl_list_entry(b->mdb_entry_list.next, struct rtnl_mdb_entry, mdb_list);
+ while (1) {
+ if ( &a_entry->mdb_list == &a->mdb_entry_list
+ || &b_entry->mdb_list == &b->mdb_entry_list) {
+ if ( &a_entry->mdb_list != &a->mdb_entry_list
+ || &b_entry->mdb_list != &b->mdb_entry_list)
+ diff |= MDB_ATTR_ENTRIES;
+ break;
+ }
+ if (!mdb_entry_equal(a_entry, b_entry)) {
+ diff |= MDB_ATTR_ENTRIES;
+ break;
+ }
+ a_entry = nl_list_entry(a_entry->mdb_list.next, struct rtnl_mdb_entry, mdb_list);
+ b_entry = nl_list_entry(b_entry->mdb_list.next, struct rtnl_mdb_entry, mdb_list);
+ }
+
+ return diff;
+}
+
+static struct rtnl_mdb_entry *mdb_entry_clone(struct rtnl_mdb_entry *src)
+{
+ struct rtnl_mdb_entry *dst = rtnl_mdb_entry_alloc();
+ if (!dst)
+ return NULL;
+
+ dst->ifindex = src->ifindex;
+ dst->state = src->state;
+ dst->vid = src->vid;
+ dst->proto = src->proto;
+
+ dst->addr = nl_addr_clone(src->addr);
+ if (dst->addr == NULL) {
+ free(dst);
+ return NULL;
+ }
+
+ return dst;
+}
+
+static int mdb_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+ struct rtnl_mdb *dst = nl_object_priv(_dst);
+ struct rtnl_mdb *src = nl_object_priv(_src);
+ struct rtnl_mdb_entry *entry;
+
+ nl_init_list_head(&dst->mdb_entry_list);
+
+ nl_list_for_each_entry(entry, &src->mdb_entry_list, mdb_list) {
+ struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
+
+ if (!copy)
+ return -NLE_NOMEM;
+
+ rtnl_mdb_add_entry(dst, copy);
+ }
+
+ return 0;
+}
+
+static int mdb_update(struct nl_object *old_obj, struct nl_object *new_obj)
+{
+ struct rtnl_mdb *old = (struct rtnl_mdb *) old_obj;
+ struct rtnl_mdb *new = (struct rtnl_mdb *) new_obj;
+ struct rtnl_mdb_entry *entry, *old_entry;
+ int action = new_obj->ce_msgtype;
+
+ if (new->ifindex != old->ifindex)
+ return -NLE_OPNOTSUPP;
+
+ switch (action) {
+ case RTM_NEWMDB:
+ nl_list_for_each_entry(entry, &new->mdb_entry_list, mdb_list) {
+ struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
+
+ if (!copy)
+ return -NLE_NOMEM;
+
+ rtnl_mdb_add_entry(old, copy);
+ }
+ break;
+ case RTM_DELMDB:
+ entry = nl_list_first_entry(&new->mdb_entry_list,
+ struct rtnl_mdb_entry,
+ mdb_list);
+ nl_list_for_each_entry(old_entry, &old->mdb_entry_list, mdb_list) {
+ if ( old_entry->ifindex == entry->ifindex
+ && !nl_addr_cmp(old_entry->addr, entry->addr)) {
+ nl_list_del(&old_entry->mdb_list);
+ break;
+ }
+ }
+ break;
+ }
+
+ return NLE_SUCCESS;
+}
+
+static struct nla_policy mdb_policy[MDBA_MAX + 1] = {
+ [MDBA_MDB] = {.type = NLA_NESTED},
+};
+
+static struct nla_policy mdb_db_policy[MDBA_MDB_MAX + 1] = {
+ [MDBA_MDB_ENTRY] = {.type = NLA_NESTED},
+};
+
+static int mdb_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+ struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+ int err = 0;
+ int rem = 0;
+ struct nlattr *tb[MDBA_MAX + 1];
+ struct br_port_msg *port;
+ struct nlattr *nla;
+ struct br_mdb_entry *e;
+ _nl_auto_rtnl_mdb struct rtnl_mdb *mdb = rtnl_mdb_alloc();
+
+ if (!mdb)
+ return -NLE_NOMEM;
+
+ err = nlmsg_parse(nlh, sizeof(struct br_port_msg), tb, MDBA_MAX,
+ mdb_policy);
+ if (err < 0)
+ return err;
+
+ mdb->ce_msgtype = nlh->nlmsg_type;
+
+ port = nlmsg_data(nlh);
+ mdb->ifindex = port->ifindex;
+ mdb->ce_mask |= MDB_ATTR_IFINDEX;
+
+ if (tb[MDBA_MDB]) {
+ struct nlattr *db_attr[MDBA_MDB_MAX+1];
+
+ err = nla_parse_nested(db_attr, MDBA_MDB_MAX, tb[MDBA_MDB],
+ mdb_db_policy);
+ if (err < 0)
+ return err;
+ rem = nla_len(tb[MDBA_MDB]);
+
+ for (nla = nla_data(tb[MDBA_MDB]); nla_ok(nla, rem);
+ nla = nla_next(nla, &rem)) {
+ int rm = nla_len(nla);
+ struct nlattr *nla2;
+
+ for (nla2 = nla_data(nla); nla_ok(nla2, rm);
+ nla2 = nla_next(nla2, &rm)) {
+ _nl_auto_nl_addr struct nl_addr *addr = NULL;
+ struct rtnl_mdb_entry *entry;
+ uint16_t proto;
+
+ e = nla_data(nla2);
+
+ proto = ntohs(e->addr.proto);
+
+ if (proto == ETH_P_IP) {
+ addr = nl_addr_build(
+ AF_INET, &e->addr.u.ip4,
+ sizeof(e->addr.u.ip4));
+ } else if (proto == ETH_P_IPV6) {
+ addr = nl_addr_build(
+ AF_INET6, &e->addr.u.ip6,
+ sizeof(e->addr.u.ip6));
+ } else {
+ addr = nl_addr_build(
+ AF_LLC, e->addr.u.mac_addr,
+ sizeof(e->addr.u.mac_addr));
+ }
+ if (!addr)
+ return -NLE_NOMEM;
+
+ entry = rtnl_mdb_entry_alloc();
+ if (!entry)
+ return -NLE_NOMEM;
+
+ mdb->ce_mask |= MDB_ATTR_ENTRIES;
+
+ entry->ifindex = e->ifindex;
+ entry->vid = e->vid;
+ entry->state = e->state;
+ entry->proto = ntohs(e->addr.proto);
+ entry->addr = _nl_steal_pointer(&addr);
+ rtnl_mdb_add_entry(mdb, entry);
+ }
+ }
+ }
+
+ return pp->pp_cb((struct nl_object *) mdb, pp);
+}
+
+static int mdb_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+ return nl_rtgen_request(sk, RTM_GETMDB, AF_BRIDGE, NLM_F_DUMP);
+}
+
+static void mdb_entry_dump_line(struct rtnl_mdb_entry *entry,
+ struct nl_dump_params *p)
+{
+ char buf[INET6_ADDRSTRLEN];
+
+ nl_dump(p, "port %d ", entry->ifindex);
+ nl_dump(p, "vid %d ", entry->vid);
+ nl_dump(p, "proto 0x%04x ", entry->proto);
+ nl_dump(p, "address %s\n", nl_addr2str(entry->addr, buf, sizeof(buf)));
+}
+
+static void mdb_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+ struct rtnl_mdb *mdb = (struct rtnl_mdb *) obj;
+ struct rtnl_mdb_entry *_mdb;
+
+ nl_dump(p, "dev %d \n", mdb->ifindex);
+
+ nl_list_for_each_entry(_mdb, &mdb->mdb_entry_list, mdb_list) {
+ p->dp_ivar = NH_DUMP_FROM_ONELINE;
+ mdb_entry_dump_line(_mdb, p);
+ }
+}
+
+static void mdb_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+ mdb_dump_line(obj, p);
+}
+
+static void mdb_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+ mdb_dump_details(obj, p);
+}
+
+void rtnl_mdb_put(struct rtnl_mdb *mdb)
+{
+ nl_object_put((struct nl_object *) mdb);
+}
+
+/** @} */
+
+/**
+ * @name Cache Management
+ * @{
+ */
+int rtnl_mdb_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+ return nl_cache_alloc_and_fill(&rtnl_mdb_ops, sk, result);
+}
+
+/**
+ * Build a neighbour cache including all MDB entries currently configured in the kernel.
+ * @arg sock Netlink socket.
+ * @arg result Pointer to store resulting cache.
+ * @arg flags Flags to apply to cache before filling
+ *
+ * Allocates a new MDB cache, initializes it properly and updates it
+ * to include all Multicast Database entries currently configured in the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_mdb_alloc_cache_flags(struct nl_sock *sock, struct nl_cache **result,
+ unsigned int flags)
+{
+ struct nl_cache *cache;
+ int err;
+
+ cache = nl_cache_alloc(&rtnl_mdb_ops);
+ if (!cache)
+ return -NLE_NOMEM;
+
+ nl_cache_set_flags(cache, flags);
+
+ if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
+ nl_cache_free(cache);
+ return err;
+ }
+
+ *result = cache;
+ return 0;
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+uint32_t rtnl_mdb_get_ifindex(struct rtnl_mdb *mdb)
+{
+ return mdb->ifindex;
+}
+
+void rtnl_mdb_add_entry(struct rtnl_mdb *mdb, struct rtnl_mdb_entry *entry)
+{
+ nl_list_add_tail(&entry->mdb_list, &mdb->mdb_entry_list);
+}
+
+void rtnl_mdb_foreach_entry(struct rtnl_mdb *mdb,
+ void (*cb)(struct rtnl_mdb_entry *, void *),
+ void *arg)
+{
+ struct rtnl_mdb_entry *entry;
+
+ nl_list_for_each_entry(entry, &mdb->mdb_entry_list, mdb_list) {
+ cb(entry, arg);
+ }
+}
+
+int rtnl_mdb_entry_get_ifindex(struct rtnl_mdb_entry *mdb_entry)
+{
+ return mdb_entry->ifindex;
+}
+
+int rtnl_mdb_entry_get_vid(struct rtnl_mdb_entry *mdb_entry)
+{
+ return mdb_entry->vid;
+}
+
+int rtnl_mdb_entry_get_state(struct rtnl_mdb_entry *mdb_entry)
+{
+ return mdb_entry->state;
+}
+
+struct nl_addr *rtnl_mdb_entry_get_addr(struct rtnl_mdb_entry *mdb_entry)
+{
+ return mdb_entry->addr;
+}
+
+uint16_t rtnl_mdb_entry_get_proto(struct rtnl_mdb_entry *mdb_entry)
+{
+ return mdb_entry->proto;
+}
+
+/** @} */
+
+static struct nl_object_ops mdb_obj_ops = {
+ .oo_name = "route/mdb",
+ .oo_size = sizeof(struct rtnl_mdb),
+ .oo_constructor = mdb_constructor,
+ .oo_dump = {
+ [NL_DUMP_LINE] = mdb_dump_line,
+ [NL_DUMP_DETAILS] = mdb_dump_details,
+ [NL_DUMP_STATS] = mdb_dump_stats,
+ },
+ .oo_clone = mdb_clone,
+ .oo_compare = mdb_compare,
+ .oo_update = mdb_update,
+ .oo_free_data = mdb_free_data,
+};
+
+struct rtnl_mdb *rtnl_mdb_alloc(void)
+{
+ return (struct rtnl_mdb *) nl_object_alloc(&mdb_obj_ops);
+}
+
+static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(void)
+{
+ struct rtnl_mdb_entry *mdb;
+
+ mdb = calloc(1, sizeof(struct rtnl_mdb_entry));
+ if (!mdb)
+ return NULL;
+
+ nl_init_list_head(&mdb->mdb_list);
+
+ return mdb;
+
+}
+
+static void rtnl_mdb_entry_free(struct rtnl_mdb_entry *mdb_entry)
+{
+ nl_list_del(&mdb_entry->mdb_list);
+ nl_addr_put(mdb_entry->addr);
+ free(mdb_entry);
+}
+
+static struct nl_af_group mdb_groups[] = {
+ {AF_BRIDGE, RTNLGRP_MDB},
+ {END_OF_GROUP_LIST},
+};
+
+static struct nl_cache_ops rtnl_mdb_ops = {
+ .co_name = "route/mdb",
+ .co_hdrsize = sizeof(struct br_port_msg),
+ .co_msgtypes = {
+ { RTM_NEWMDB, NL_ACT_NEW, "new"},
+ { RTM_DELMDB, NL_ACT_DEL, "del"},
+ { RTM_GETMDB, NL_ACT_GET, "get"},
+ END_OF_MSGTYPES_LIST,
+ },
+ .co_protocol = NETLINK_ROUTE,
+ .co_groups = mdb_groups,
+ .co_request_update = mdb_request_update,
+ .co_msg_parser = mdb_msg_parser,
+ .co_obj_ops = &mdb_obj_ops,
+};
+
+static void __init mdb_init(void)
+{
+ nl_cache_mngt_register(&rtnl_mdb_ops);
+}
+
+static void __exit mdb_exit(void)
+{
+ nl_cache_mngt_unregister(&rtnl_mdb_ops);
+}
+
+/** @} */
diff --git a/lib/route/neigh.c b/lib/route/neigh.c
index ca4f2b66..e1ef6a14 100644
--- a/lib/route/neigh.c
+++ b/lib/route/neigh.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/neigh.c Neighbours
- *
- * 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-2008 Thomas Graf <tgraf@suug.ch>
*/
@@ -192,6 +185,9 @@ static int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
struct rtnl_neigh *dst = nl_object_priv(_dst);
struct rtnl_neigh *src = nl_object_priv(_src);
+ dst->n_lladdr = NULL;
+ dst->n_dst = NULL;
+
if (src->n_lladdr)
if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
return -NLE_NOMEM;
@@ -716,7 +712,7 @@ static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
goto nla_put_failure;
- if (tmpl->n_family != AF_BRIDGE)
+ if (tmpl->ce_mask & NEIGH_ATTR_DST)
NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
diff --git a/lib/route/neightbl.c b/lib/route/neightbl.c
index 96ca44a1..c4244fc6 100644
--- a/lib/route/neightbl.c
+++ b/lib/route/neightbl.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/neightbl.c neighbour tables
- *
- * 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-2008 Thomas Graf <tgraf@suug.ch>
*/
@@ -18,6 +11,7 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/utils.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/rtnl.h>
@@ -25,31 +19,31 @@
#include <netlink/route/link.h>
/** @cond SKIP */
-#define NEIGHTBL_ATTR_FAMILY 0x001
-#define NEIGHTBL_ATTR_STATS 0x002
-#define NEIGHTBL_ATTR_NAME 0x004
-#define NEIGHTBL_ATTR_THRESH1 0x008
-#define NEIGHTBL_ATTR_THRESH2 0x010
-#define NEIGHTBL_ATTR_THRESH3 0x020
-#define NEIGHTBL_ATTR_CONFIG 0x040
-#define NEIGHTBL_ATTR_PARMS 0x080
-#define NEIGHTBL_ATTR_GC_INTERVAL 0x100
-
-#define NEIGHTBLPARM_ATTR_IFINDEX 0x0001
-#define NEIGHTBLPARM_ATTR_REFCNT 0x0002
-#define NEIGHTBLPARM_ATTR_QUEUE_LEN 0x0004
-#define NEIGHTBLPARM_ATTR_APP_PROBES 0x0008
-#define NEIGHTBLPARM_ATTR_UCAST_PROBES 0x0010
-#define NEIGHTBLPARM_ATTR_MCAST_PROBES 0x0020
-#define NEIGHTBLPARM_ATTR_PROXY_QLEN 0x0040
-#define NEIGHTBLPARM_ATTR_REACHABLE_TIME 0x0080
+#define NEIGHTBL_ATTR_FAMILY 0x001
+#define NEIGHTBL_ATTR_STATS 0x002
+#define NEIGHTBL_ATTR_NAME 0x004
+#define NEIGHTBL_ATTR_THRESH1 0x008
+#define NEIGHTBL_ATTR_THRESH2 0x010
+#define NEIGHTBL_ATTR_THRESH3 0x020
+#define NEIGHTBL_ATTR_CONFIG 0x040
+#define NEIGHTBL_ATTR_PARMS 0x080
+#define NEIGHTBL_ATTR_GC_INTERVAL 0x100
+
+#define NEIGHTBLPARM_ATTR_IFINDEX 0x0001
+#define NEIGHTBLPARM_ATTR_REFCNT 0x0002
+#define NEIGHTBLPARM_ATTR_QUEUE_LEN 0x0004
+#define NEIGHTBLPARM_ATTR_APP_PROBES 0x0008
+#define NEIGHTBLPARM_ATTR_UCAST_PROBES 0x0010
+#define NEIGHTBLPARM_ATTR_MCAST_PROBES 0x0020
+#define NEIGHTBLPARM_ATTR_PROXY_QLEN 0x0040
+#define NEIGHTBLPARM_ATTR_REACHABLE_TIME 0x0080
#define NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME 0x0100
-#define NEIGHTBLPARM_ATTR_RETRANS_TIME 0x0200
-#define NEIGHTBLPARM_ATTR_GC_STALETIME 0x0400
+#define NEIGHTBLPARM_ATTR_RETRANS_TIME 0x0200
+#define NEIGHTBLPARM_ATTR_GC_STALETIME 0x0400
#define NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME 0x0800
-#define NEIGHTBLPARM_ATTR_ANYCAST_DELAY 0x1000
-#define NEIGHTBLPARM_ATTR_PROXY_DELAY 0x2000
-#define NEIGHTBLPARM_ATTR_LOCKTIME 0x4000
+#define NEIGHTBLPARM_ATTR_ANYCAST_DELAY 0x1000
+#define NEIGHTBLPARM_ATTR_PROXY_DELAY 0x2000
+#define NEIGHTBLPARM_ATTR_LOCKTIME 0x4000
static struct nl_cache_ops rtnl_neightbl_ops;
static struct nl_object_ops neightbl_obj_ops;
@@ -58,18 +52,18 @@ static struct nl_object_ops neightbl_obj_ops;
static uint64_t neightbl_compare(struct nl_object *_a, struct nl_object *_b,
uint64_t attrs, int flags)
{
- struct rtnl_neightbl *a = (struct rtnl_neightbl *) _a;
- struct rtnl_neightbl *b = (struct rtnl_neightbl *) _b;
+ struct rtnl_neightbl *a = (struct rtnl_neightbl *)_a;
+ struct rtnl_neightbl *b = (struct rtnl_neightbl *)_b;
uint64_t diff = 0;
#define NT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGHTBL_ATTR_##ATTR, a, b, EXPR)
- diff |= NT_DIFF(FAMILY, a->nt_family != b->nt_family);
- diff |= NT_DIFF(NAME, strcmp(a->nt_name, b->nt_name));
- diff |= NT_DIFF(THRESH1, a->nt_gc_thresh1 != b->nt_gc_thresh1);
- diff |= NT_DIFF(THRESH2, a->nt_gc_thresh2 != b->nt_gc_thresh2);
- diff |= NT_DIFF(THRESH3, a->nt_gc_thresh3 != b->nt_gc_thresh3);
- diff |= NT_DIFF(GC_INTERVAL, a->nt_gc_interval != b->nt_gc_interval);
+ diff |= NT_DIFF(FAMILY, a->nt_family != b->nt_family);
+ diff |= NT_DIFF(NAME, strcmp(a->nt_name, b->nt_name));
+ diff |= NT_DIFF(THRESH1, a->nt_gc_thresh1 != b->nt_gc_thresh1);
+ diff |= NT_DIFF(THRESH2, a->nt_gc_thresh2 != b->nt_gc_thresh2);
+ diff |= NT_DIFF(THRESH3, a->nt_gc_thresh3 != b->nt_gc_thresh3);
+ diff |= NT_DIFF(GC_INTERVAL, a->nt_gc_interval != b->nt_gc_interval);
#undef NT_DIFF
@@ -77,8 +71,7 @@ static uint64_t neightbl_compare(struct nl_object *_a, struct nl_object *_b,
!(b->ce_mask & NEIGHTBL_ATTR_PARMS))
return diff;
- /* XXX: FIXME: Compare parameter table */
-
+ /* XXX: FIXME: Compare parameter table */
#if 0
#define REQ(F) (fp->ntp_mask & NEIGHTBLPARM_ATTR_##F)
@@ -106,17 +99,15 @@ static uint64_t neightbl_compare(struct nl_object *_a, struct nl_object *_b,
return diff;
}
-
-static struct nla_policy neightbl_policy[NDTA_MAX+1] = {
- [NDTA_NAME] = { .type = NLA_STRING,
- .maxlen = NTBLNAMSIZ },
- [NDTA_THRESH1] = { .type = NLA_U32 },
- [NDTA_THRESH2] = { .type = NLA_U32 },
- [NDTA_THRESH3] = { .type = NLA_U32 },
- [NDTA_GC_INTERVAL] = { .type = NLA_U32 },
- [NDTA_CONFIG] = { .minlen = sizeof(struct ndt_config) },
- [NDTA_STATS] = { .minlen = sizeof(struct ndt_stats) },
- [NDTA_PARMS] = { .type = NLA_NESTED },
+static struct nla_policy neightbl_policy[NDTA_MAX + 1] = {
+ [NDTA_NAME] = { .type = NLA_STRING, .maxlen = NTBLNAMSIZ },
+ [NDTA_THRESH1] = { .type = NLA_U32 },
+ [NDTA_THRESH2] = { .type = NLA_U32 },
+ [NDTA_THRESH3] = { .type = NLA_U32 },
+ [NDTA_GC_INTERVAL] = { .type = NLA_U32 },
+ [NDTA_CONFIG] = { .minlen = sizeof(struct ndt_config) },
+ [NDTA_STATS] = { .minlen = sizeof(struct ndt_stats) },
+ [NDTA_PARMS] = { .type = NLA_NESTED },
};
static int neightbl_msg_parser(struct nl_cache_ops *ops,
@@ -191,11 +182,11 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops,
if (err < 0)
goto errout;
-#define COPY_ENTRY(name, var) \
- if (tbp[NDTPA_ ##name]) { \
- p->ntp_ ##var = nla_get_u32(tbp[NDTPA_ ##name]); \
- p->ntp_mask |= NEIGHTBLPARM_ATTR_ ##name; \
- }
+#define COPY_ENTRY(name, var) \
+ if (tbp[NDTPA_##name]) { \
+ p->ntp_##var = nla_get_u32(tbp[NDTPA_##name]); \
+ p->ntp_mask |= NEIGHTBLPARM_ATTR_##name; \
+ }
COPY_ENTRY(IFINDEX, ifindex);
COPY_ENTRY(REFCNT, refcnt);
@@ -217,7 +208,7 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops,
ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
}
- err = pp->pp_cb((struct nl_object *) ntbl, pp);
+ err = pp->pp_cb((struct nl_object *)ntbl, pp);
errout:
rtnl_neightbl_put(ntbl);
return err;
@@ -228,10 +219,9 @@ static int neightbl_request_update(struct nl_cache *c, struct nl_sock *h)
return nl_rtgen_request(h, RTM_GETNEIGHTBL, AF_UNSPEC, NLM_F_DUMP);
}
-
static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p)
{
- struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+ struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *)arg;
nl_dump_line(p, "%s", ntbl->nt_name);
@@ -267,101 +257,102 @@ static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p)
nl_dump(p, "\n");
}
-static void neightbl_dump_details(struct nl_object *arg, struct nl_dump_params *p)
+static void neightbl_dump_details(struct nl_object *arg,
+ struct nl_dump_params *p)
{
char x[32], y[32], z[32];
- struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+ struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *)arg;
neightbl_dump_line(arg, p);
if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) {
nl_dump_line(p, " key-len %u entry-size %u last-flush %s\n",
- ntbl->nt_config.ndtc_key_len,
- ntbl->nt_config.ndtc_entry_size,
- nl_msec2str(ntbl->nt_config.ndtc_last_flush,
- x, sizeof(x)));
-
- nl_dump_line(p, " gc threshold %u/%u/%u interval %s " \
- "chain-position %u\n",
- ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2,
- ntbl->nt_gc_thresh3,
- nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)),
- ntbl->nt_config.ndtc_hash_chain_gc);
+ ntbl->nt_config.ndtc_key_len,
+ ntbl->nt_config.ndtc_entry_size,
+ nl_msec2str(ntbl->nt_config.ndtc_last_flush, x,
+ sizeof(x)));
+
+ nl_dump_line(p,
+ " gc threshold %u/%u/%u interval %s "
+ "chain-position %u\n",
+ ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2,
+ ntbl->nt_gc_thresh3,
+ nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)),
+ ntbl->nt_config.ndtc_hash_chain_gc);
nl_dump_line(p, " hash-rand 0x%08X/0x%08X last-rand %s\n",
- ntbl->nt_config.ndtc_hash_rnd,
- ntbl->nt_config.ndtc_hash_mask,
- nl_msec2str(ntbl->nt_config.ndtc_last_rand,
- x, sizeof(x)));
+ ntbl->nt_config.ndtc_hash_rnd,
+ ntbl->nt_config.ndtc_hash_mask,
+ nl_msec2str(ntbl->nt_config.ndtc_last_rand, x,
+ sizeof(x)));
}
if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
- nl_dump_line(p, " refcnt %u pending-queue-limit %u " \
- "proxy-delayed-queue-limit %u\n",
- pa->ntp_refcnt,
- pa->ntp_queue_len,
- pa->ntp_proxy_qlen);
-
- nl_dump_line(p, " num-userspace-probes %u num-unicast-probes " \
- "%u num-multicast-probes %u\n",
- pa->ntp_app_probes,
- pa->ntp_ucast_probes,
- pa->ntp_mcast_probes);
-
- nl_dump_line(p, " min-age %s base-reachable-time %s " \
- "stale-check-interval %s\n",
- nl_msec2str(pa->ntp_locktime, x, sizeof(x)),
- nl_msec2str(pa->ntp_base_reachable_time,
- y, sizeof(y)),
- nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z)));
-
- nl_dump_line(p, " initial-probe-delay %s answer-delay %s " \
- "proxy-answer-delay %s\n",
- nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)),
- nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)),
- nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z)));
+ nl_dump_line(p,
+ " refcnt %u pending-queue-limit %u "
+ "proxy-delayed-queue-limit %u\n",
+ pa->ntp_refcnt, pa->ntp_queue_len,
+ pa->ntp_proxy_qlen);
+
+ nl_dump_line(p,
+ " num-userspace-probes %u num-unicast-probes "
+ "%u num-multicast-probes %u\n",
+ pa->ntp_app_probes, pa->ntp_ucast_probes,
+ pa->ntp_mcast_probes);
+
+ nl_dump_line(p,
+ " min-age %s base-reachable-time %s "
+ "stale-check-interval %s\n",
+ nl_msec2str(pa->ntp_locktime, x, sizeof(x)),
+ nl_msec2str(pa->ntp_base_reachable_time, y,
+ sizeof(y)),
+ nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z)));
+
+ nl_dump_line(p,
+ " initial-probe-delay %s answer-delay %s "
+ "proxy-answer-delay %s\n",
+ nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)),
+ nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)),
+ nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z)));
}
}
static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
{
- struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+ struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *)arg;
neightbl_dump_details(arg, p);
if (!(ntbl->ce_mask & NEIGHTBL_ATTR_STATS))
return;
- nl_dump_line(p, " " \
- " lookups %" PRIu64 \
- " hits %" PRIu64 \
- " failed %" PRIu64 \
- " allocations %" PRIu64 \
- " destroys %" PRIu64 \
- "\n",
- ntbl->nt_stats.ndts_lookups,
- ntbl->nt_stats.ndts_hits,
- ntbl->nt_stats.ndts_res_failed,
- ntbl->nt_stats.ndts_allocs,
- ntbl->nt_stats.ndts_destroys);
-
- nl_dump_line(p, " " \
- " hash-grows %" PRIu64 \
- " forced-gc-runs %" PRIu64 \
- " periodic-gc-runs %" PRIu64 \
- "\n",
- ntbl->nt_stats.ndts_hash_grows,
- ntbl->nt_stats.ndts_forced_gc_runs,
- ntbl->nt_stats.ndts_periodic_gc_runs);
-
- nl_dump_line(p, " " \
- " rcv-unicast-probes %" PRIu64 \
- " rcv-multicast-probes %" PRIu64 \
- "\n",
- ntbl->nt_stats.ndts_rcv_probes_ucast,
- ntbl->nt_stats.ndts_rcv_probes_mcast);
+ nl_dump_line(p,
+ " "
+ " lookups %llu hits %llu failed %llu"
+ " allocations %llu destroys %llu\n",
+ (long long unsigned)ntbl->nt_stats.ndts_lookups,
+ (long long unsigned)ntbl->nt_stats.ndts_hits,
+ (long long unsigned)ntbl->nt_stats.ndts_res_failed,
+ (long long unsigned)ntbl->nt_stats.ndts_allocs,
+ (long long unsigned)ntbl->nt_stats.ndts_destroys);
+
+ nl_dump_line(p,
+ " "
+ " hash-grows %llu forced-gc-runs %llu"
+ " periodic-gc-runs %llu\n",
+ (long long unsigned)ntbl->nt_stats.ndts_hash_grows,
+ (long long unsigned)ntbl->nt_stats.ndts_forced_gc_runs,
+ (long long unsigned)ntbl->nt_stats.ndts_periodic_gc_runs);
+
+ nl_dump_line(p,
+ " "
+ " rcv-unicast-probes %llu"
+ " rcv-multicast-probes %llu"
+ "\n",
+ (long long unsigned)ntbl->nt_stats.ndts_rcv_probes_ucast,
+ (long long unsigned)ntbl->nt_stats.ndts_rcv_probes_mcast);
}
/**
@@ -371,12 +362,12 @@ static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
struct rtnl_neightbl *rtnl_neightbl_alloc(void)
{
- return (struct rtnl_neightbl *) nl_object_alloc(&neightbl_obj_ops);
+ return (struct rtnl_neightbl *)nl_object_alloc(&neightbl_obj_ops);
}
void rtnl_neightbl_put(struct rtnl_neightbl *neightbl)
{
- nl_object_put((struct nl_object *) neightbl);
+ nl_object_put((struct nl_object *)neightbl);
}
/** @} */
@@ -423,11 +414,11 @@ struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache,
if (cache->c_ops != &rtnl_neightbl_ops)
return NULL;
- nl_list_for_each_entry(nt, &cache->c_items, ce_list) {
+ nl_list_for_each_entry (nt, &cache->c_items, ce_list) {
if (!strcasecmp(nt->nt_name, name) &&
((!ifindex && !nt->nt_parms.ntp_ifindex) ||
(ifindex && ifindex == nt->nt_parms.ntp_ifindex))) {
- nl_object_get((struct nl_object *) nt);
+ nl_object_get((struct nl_object *)nt);
return nt;
}
}
@@ -486,8 +477,7 @@ int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
if (tmpl->ce_mask & NEIGHTBL_ATTR_GC_INTERVAL)
- NLA_PUT_U64(m, NDTA_GC_INTERVAL,
- tmpl->nt_gc_interval);
+ NLA_PUT_U64(m, NDTA_GC_INTERVAL, tmpl->nt_gc_interval);
if (tmpl->ce_mask & NEIGHTBL_ATTR_PARMS) {
struct rtnl_neightbl_parms *p = &tmpl->nt_parms;
@@ -498,8 +488,7 @@ int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
if (old->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX)
NLA_PUT_U32(parms, NDTPA_IFINDEX,
- old->nt_parms.ntp_ifindex);
-
+ old->nt_parms.ntp_ifindex);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_QUEUE_LEN)
NLA_PUT_U32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len);
@@ -516,8 +505,7 @@ int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
p->ntp_mcast_probes);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_QLEN)
- NLA_PUT_U32(parms, NDTPA_PROXY_QLEN,
- p->ntp_proxy_qlen);
+ NLA_PUT_U32(parms, NDTPA_PROXY_QLEN, p->ntp_proxy_qlen);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME)
NLA_PUT_U64(parms, NDTPA_BASE_REACHABLE_TIME,
@@ -541,7 +529,7 @@ int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_DELAY)
NLA_PUT_U64(parms, NDTPA_PROXY_DELAY,
- p->ntp_proxy_delay);
+ p->ntp_proxy_delay);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_LOCKTIME)
NLA_PUT_U64(parms, NDTPA_LOCKTIME, p->ntp_locktime);
@@ -580,7 +568,7 @@ int rtnl_neightbl_change(struct nl_sock *sk, struct rtnl_neightbl *old,
{
struct nl_msg *msg;
int err;
-
+
if ((err = rtnl_neightbl_build_change_request(old, tmpl, &msg)) < 0)
return err;
@@ -631,7 +619,7 @@ void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *ntbl, int thresh)
void rtnl_neightbl_set_name(struct rtnl_neightbl *ntbl, const char *name)
{
- strncpy(ntbl->nt_name, name, sizeof(ntbl->nt_name) - 1);
+ _nl_strncpy_trunc(ntbl->nt_name, name, sizeof(ntbl->nt_name));
ntbl->ce_mask |= NEIGHTBL_ATTR_NAME;
}
diff --git a/lib/route/netconf.c b/lib/route/netconf.c
index a11ad0e2..50c91bfe 100644
--- a/lib/route/netconf.c
+++ b/lib/route/netconf.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/netconf.c netconf
- *
- * 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 David Ahern <dsa@cumulusnetworks.com>
*/
@@ -81,16 +74,6 @@ static struct rtnl_netconf *rtnl_netconf_alloc(void)
return (struct rtnl_netconf *) nl_object_alloc(&netconf_obj_ops);
}
-static int netconf_clone(struct nl_object *_dst, struct nl_object *_src)
-{
- struct rtnl_netconf *dst = nl_object_priv(_dst);
- struct rtnl_netconf *src = nl_object_priv(_src);
-
- *dst = *src;
-
- return 0;
-}
-
static int netconf_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *nlh, struct nl_parser_param *pp)
{
@@ -535,7 +518,6 @@ int rtnl_netconf_get_input(struct rtnl_netconf *nc, int *val)
static struct nl_object_ops netconf_obj_ops = {
.oo_name = "route/netconf",
.oo_size = sizeof(struct rtnl_netconf),
- .oo_clone = netconf_clone,
.oo_dump = {
[NL_DUMP_LINE] = netconf_dump_line,
[NL_DUMP_DETAILS] = netconf_dump_line,
diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c
index 7a9904c9..68351371 100644
--- a/lib/route/nexthop.c
+++ b/lib/route/nexthop.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/nexthop.c Routing Nexthop
- *
- * 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-2008 Thomas Graf <tgraf@suug.ch>
*/
@@ -351,10 +344,6 @@ int rtnl_route_nh_set_newdst(struct rtnl_nexthop *nh, struct nl_addr *addr)
{
struct nl_addr *old = nh->rtnh_newdst;
- if (!nl_addr_valid(nl_addr_get_binary_addr(addr),
- nl_addr_get_len(addr)))
- return -NLE_INVAL;
-
if (addr) {
nh->rtnh_newdst = nl_addr_get(addr);
nh->ce_mask |= NH_ATTR_NEWDST;
@@ -378,10 +367,6 @@ int rtnl_route_nh_set_via(struct rtnl_nexthop *nh, struct nl_addr *addr)
{
struct nl_addr *old = nh->rtnh_via;
- if (!nl_addr_valid(nl_addr_get_binary_addr(addr),
- nl_addr_get_len(addr)))
- return -NLE_INVAL;
-
if (addr) {
nh->rtnh_via = nl_addr_get(addr);
nh->ce_mask |= NH_ATTR_VIA;
diff --git a/lib/route/nexthop_encap.c b/lib/route/nexthop_encap.c
index 21f647a7..2382886a 100644
--- a/lib/route/nexthop_encap.c
+++ b/lib/route/nexthop_encap.c
@@ -31,10 +31,13 @@ static const char *nh_encap_type2str(unsigned int type)
void nh_encap_dump(struct rtnl_nh_encap *rtnh_encap, struct nl_dump_params *dp)
{
+ if (!rtnh_encap->ops)
+ return;
+
nl_dump(dp, " encap %s ",
nh_encap_type2str(rtnh_encap->ops->encap_type));
- if (rtnh_encap->ops && rtnh_encap->ops->dump)
+ if (rtnh_encap->ops->dump)
rtnh_encap->ops->dump(rtnh_encap->priv, dp);
}
@@ -55,7 +58,7 @@ int nh_encap_build_msg(struct nl_msg *msg, struct rtnl_nh_encap *rtnh_encap)
goto nla_put_failure;
err = rtnh_encap->ops->build_msg(msg, rtnh_encap->priv);
- if (err)
+ if (err < 0)
return err;
nla_nest_end(msg, encap);
diff --git a/lib/route/nh_encap_mpls.c b/lib/route/nh_encap_mpls.c
index 081661e6..d30acc2c 100644
--- a/lib/route/nh_encap_mpls.c
+++ b/lib/route/nh_encap_mpls.c
@@ -34,7 +34,7 @@ static int mpls_encap_build_msg(struct nl_msg *msg, void *priv)
return 0;
nla_put_failure:
- return -NLE_MSGSIZE;
+ return -NLE_MSGSIZE;
}
static void mpls_encap_destructor(void *priv)
@@ -56,9 +56,8 @@ static int mpls_encap_parse_msg(struct nlattr *nla, struct rtnl_nexthop *nh)
uint8_t ttl = 0;
int err;
-
err = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla, mpls_encap_policy);
- if (err)
+ if (err < 0)
return err;
if (!tb[MPLS_IPTUNNEL_DST])
@@ -109,10 +108,6 @@ int rtnl_route_nh_encap_mpls(struct rtnl_nexthop *nh,
if (!addr)
return -NLE_INVAL;
- if (!nl_addr_valid(nl_addr_get_binary_addr(addr),
- nl_addr_get_len(addr)))
- return -NLE_INVAL;
-
rtnh_encap = calloc(1, sizeof(*rtnh_encap));
if (!rtnh_encap)
return -NLE_NOMEM;
@@ -133,3 +128,31 @@ int rtnl_route_nh_encap_mpls(struct rtnl_nexthop *nh,
return 0;
}
+
+struct nl_addr *rtnl_route_nh_get_encap_mpls_dst(struct rtnl_nexthop *nh)
+{
+ struct mpls_iptunnel_encap *mpls_encap;
+
+ if (!nh->rtnh_encap || nh->rtnh_encap->ops->encap_type != LWTUNNEL_ENCAP_MPLS)
+ return NULL;
+
+ mpls_encap = (struct mpls_iptunnel_encap *)nh->rtnh_encap->priv;
+ if (!mpls_encap)
+ return NULL;
+
+ return mpls_encap->dst;
+}
+
+uint8_t rtnl_route_nh_get_encap_mpls_ttl(struct rtnl_nexthop *nh)
+{
+ struct mpls_iptunnel_encap *mpls_encap;
+
+ if (!nh->rtnh_encap || nh->rtnh_encap->ops->encap_type != LWTUNNEL_ENCAP_MPLS)
+ return 0;
+
+ mpls_encap = (struct mpls_iptunnel_encap *)nh->rtnh_encap->priv;
+ if (!mpls_encap)
+ return 0;
+
+ return mpls_encap->ttl;
+}
diff --git a/lib/route/pktloc.c b/lib/route/pktloc.c
index 9462c6e2..599e5930 100644
--- a/lib/route/pktloc.c
+++ b/lib/route/pktloc.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/pktloc.c Packet Location Aliasing
- *
- * 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>
*/
@@ -124,7 +117,7 @@ static int read_pktlocs(void)
nl_init_list_head(&pktloc_name_ht[i]);
}
- if ((err = pktloc_lex_init(&scanner)) < 0) {
+ if (pktloc_lex_init(&scanner) < 0) {
err = -NLE_FAILURE;
goto errout_close;
}
diff --git a/lib/route/pktloc_syntax.y b/lib/route/pktloc_syntax.y
index 25d87109..3c9326fe 100644
--- a/lib/route/pktloc_syntax.y
+++ b/lib/route/pktloc_syntax.y
@@ -24,6 +24,7 @@
%{
extern int pktloc_lex(YYSTYPE *, YYLTYPE *, void *);
+#define pktloc_error yyerror
static void yyerror(YYLTYPE *locp, void *scanner, const char *msg)
{
NL_DBG(1, "Error while parsing packet location file: %s\n", msg);
diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c
index 7413cf7e..62c4390a 100644
--- a/lib/route/qdisc.c
+++ b/lib/route/qdisc.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc.c Queueing Disciplines
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
@@ -404,6 +397,38 @@ struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *cache,
}
/**
+ * Search qdisc by kind
+ * @arg cache Qdisc cache
+ * @arg ifindex Interface index
+ * @arg kind Qdisc kind (tbf, htb, cbq, etc)
+ *
+ * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache()
+ * and searches for a qdisc matching the interface index and kind.
+ *
+ * The reference counter is incremented before returning the qdisc, therefore
+ * the reference must be given back with rtnl_qdisc_put() after usage.
+ *
+ * @return pointer to qdisc inside the cache or NULL if no match was found.
+ */
+struct rtnl_qdisc *rtnl_qdisc_get_by_kind(struct nl_cache *cache,
+ int ifindex, char *kind)
+{
+ struct rtnl_qdisc *q;
+
+ if (cache->c_ops != &rtnl_qdisc_ops)
+ return NULL;
+
+ nl_list_for_each_entry(q, &cache->c_items, ce_list) {
+ if ((q->q_ifindex == ifindex) && (!strcmp(q->q_kind, kind))) {
+ nl_object_get((struct nl_object *) q);
+ return q;
+ }
+ }
+
+ return NULL;
+}
+
+/**
* Search qdisc by interface index and handle
* @arg cache Qdisc cache
* @arg ifindex Interface index
diff --git a/lib/route/qdisc/blackhole.c b/lib/route/qdisc/blackhole.c
index 339cf781..c24507af 100644
--- a/lib/route/qdisc/blackhole.c
+++ b/lib/route/qdisc/blackhole.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/blackhole.c Blackhole Qdisc
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/qdisc/cbq.c b/lib/route/qdisc/cbq.c
index 118f893d..62af8235 100644
--- a/lib/route/qdisc/cbq.c
+++ b/lib/route/qdisc/cbq.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/cbq.c Class Based Queueing
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/qdisc/dsmark.c b/lib/route/qdisc/dsmark.c
index fd9553dc..07f938c7 100644
--- a/lib/route/qdisc/dsmark.c
+++ b/lib/route/qdisc/dsmark.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/dsmark.c DSMARK
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/qdisc/fifo.c b/lib/route/qdisc/fifo.c
index d94c0079..dc6d1895 100644
--- a/lib/route/qdisc/fifo.c
+++ b/lib/route/qdisc/fifo.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/fifo.c (p|b)fifo
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/qdisc/fq_codel.c b/lib/route/qdisc/fq_codel.c
index ade20e50..34f6b444 100644
--- a/lib/route/qdisc/fq_codel.c
+++ b/lib/route/qdisc/fq_codel.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/fq_codel.c fq_codel
- *
- * 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) 2013 Cong Wang <xiyou.wangcong@gmail.com>
*/
diff --git a/lib/route/qdisc/hfsc.c b/lib/route/qdisc/hfsc.c
index ddd12425..0167e97e 100644
--- a/lib/route/qdisc/hfsc.c
+++ b/lib/route/qdisc/hfsc.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/hfsc.c HFSC Qdisc
- *
- * 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) 2014 Cong Wang <xiyou.wangcong@gmail.com>
*/
diff --git a/lib/route/qdisc/htb.c b/lib/route/qdisc/htb.c
index e426a149..ebe38f90 100644
--- a/lib/route/qdisc/htb.c
+++ b/lib/route/qdisc/htb.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/htb.c HTB Qdisc
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
* Copyright (c) 2005-2006 Siemens AG Oesterreich
diff --git a/lib/route/qdisc/ingress.c b/lib/route/qdisc/ingress.c
index 1a63f364..73d2440e 100644
--- a/lib/route/qdisc/ingress.c
+++ b/lib/route/qdisc/ingress.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/ingress.c ingress
- *
- * 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) 2013 Cong Wang <xiyou.wangcong@gmail.com>
*/
diff --git a/lib/route/qdisc/mqprio.c b/lib/route/qdisc/mqprio.c
index 0d072476..c1654041 100644
--- a/lib/route/qdisc/mqprio.c
+++ b/lib/route/qdisc/mqprio.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/mqprio.c MQPRIO Qdisc/Class
- *
- * 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) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@westermo.se>
*/
@@ -271,14 +265,15 @@ int rtnl_qdisc_mqprio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
return -NLE_MISSING_ATTR;
- if ((len / sizeof(uint8_t)) > (TC_QOPT_BITMASK+1))
+ if (len > TC_QOPT_BITMASK + 1)
return -NLE_RANGE;
- for (i = 0; i <= TC_QOPT_BITMASK; i++) {
+ for (i = 0; i < len; i++) {
if (priomap[i] > mqprio->qm_num_tc)
return -NLE_RANGE;
}
+ memset(mqprio->qm_prio_map, 0, sizeof(mqprio->qm_prio_map));
memcpy(mqprio->qm_prio_map, priomap, len * sizeof(uint8_t));
mqprio->qm_mask |= SCH_MQPRIO_ATTR_PRIOMAP;
@@ -366,9 +361,11 @@ int rtnl_qdisc_mqprio_set_queue(struct rtnl_qdisc *qdisc, uint16_t count[],
if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
return -NLE_MISSING_ATTR;
- if ((len / sizeof(uint16_t)) > TC_QOPT_MAX_QUEUE)
+ if (len < 0 || len > TC_QOPT_MAX_QUEUE)
return -NLE_RANGE;
+ memset(mqprio->qm_count, 0, sizeof(mqprio->qm_count));
+ memset(mqprio->qm_offset, 0, sizeof(mqprio->qm_offset));
memcpy(mqprio->qm_count, count, len * sizeof(uint16_t));
memcpy(mqprio->qm_offset, offset, len * sizeof(uint16_t));
mqprio->qm_mask |= SCH_MQPRIO_ATTR_QUEUE;
@@ -499,9 +496,10 @@ int rtnl_qdisc_mqprio_set_min_rate(struct rtnl_qdisc *qdisc, uint64_t min[], int
if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
return -NLE_INVAL;
- if ((len / sizeof(uint64_t)) > TC_QOPT_MAX_QUEUE)
+ if (len < 0 || len > TC_QOPT_MAX_QUEUE)
return -NLE_RANGE;
+ memset(mqprio->qm_min_rate, 0, sizeof(mqprio->qm_min_rate));
memcpy(mqprio->qm_min_rate, min, len * sizeof(uint64_t));
mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
@@ -548,9 +546,10 @@ int rtnl_qdisc_mqprio_set_max_rate(struct rtnl_qdisc *qdisc, uint64_t max[], int
if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
return -NLE_INVAL;
- if ((len / sizeof(uint64_t)) > TC_QOPT_MAX_QUEUE)
+ if (len < 0 || len > TC_QOPT_MAX_QUEUE)
return -NLE_RANGE;
+ memset(mqprio->qm_max_rate, 0, sizeof(mqprio->qm_max_rate));
memcpy(mqprio->qm_max_rate, max, len * sizeof(uint64_t));
mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
diff --git a/lib/route/qdisc/netem.c b/lib/route/qdisc/netem.c
index 17dee3b7..0ca1d571 100644
--- a/lib/route/qdisc/netem.c
+++ b/lib/route/qdisc/netem.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/netem.c Network Emulator Qdisc
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
@@ -26,6 +20,8 @@
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc/netem.h>
+#include "netlink-private/utils.h"
+
/** @cond SKIP */
#define SCH_NETEM_ATTR_LATENCY 0x0001
#define SCH_NETEM_ATTR_LIMIT 0x0002
@@ -165,39 +161,39 @@ static void netem_dump_details(struct rtnl_tc *tc, void *data,
nl_dump(p, " jitter %s", buf);
if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR && netem->qnm_corr.nmc_delay > 0)
- nl_dump(p, " %d%", netem->qnm_corr.nmc_delay);
+ nl_dump(p, " %d", netem->qnm_corr.nmc_delay);
}
}
if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS && netem->qnm_loss > 0) {
- nl_dump(p, " loss %d%", netem->qnm_loss);
+ nl_dump(p, " loss %d", netem->qnm_loss);
if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR && netem->qnm_corr.nmc_loss > 0)
- nl_dump(p, " %d%", netem->qnm_corr.nmc_loss);
+ nl_dump(p, " %d", netem->qnm_corr.nmc_loss);
}
if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE && netem->qnm_duplicate > 0) {
- nl_dump(p, " duplicate %d%", netem->qnm_duplicate);
+ nl_dump(p, " duplicate %d", netem->qnm_duplicate);
if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR && netem->qnm_corr.nmc_duplicate > 0)
- nl_dump(p, " %d%", netem->qnm_corr.nmc_duplicate);
+ nl_dump(p, " %d", netem->qnm_corr.nmc_duplicate);
}
if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB && netem->qnm_ro.nmro_probability > 0) {
- nl_dump(p, " reorder %d%", netem->qnm_ro.nmro_probability);
+ nl_dump(p, " reorder %d", netem->qnm_ro.nmro_probability);
if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR && netem->qnm_ro.nmro_correlation > 0)
- nl_dump(p, " %d%", netem->qnm_ro.nmro_correlation);
+ nl_dump(p, " %d", netem->qnm_ro.nmro_correlation);
if (netem->qnm_mask & SCH_NETEM_ATTR_GAP && netem->qnm_gap > 0)
nl_dump(p, " gap %d", netem->qnm_gap);
}
if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB && netem->qnm_crpt.nmcr_probability > 0) {
- nl_dump(p, " reorder %d%", netem->qnm_crpt.nmcr_probability);
+ nl_dump(p, " reorder %d", netem->qnm_crpt.nmcr_probability);
if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR && netem->qnm_crpt.nmcr_correlation > 0)
- nl_dump(p, " %d%", netem->qnm_crpt.nmcr_correlation);
+ nl_dump(p, " %d", netem->qnm_crpt.nmcr_correlation);
}
}
}
@@ -911,10 +907,10 @@ int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist
int n = 0;
size_t i;
size_t len = 2048;
- char *line;
+ _nl_auto_free char *line = NULL;
char name[NAME_MAX];
char dist_suffix[] = ".dist";
- int16_t *data;
+ _nl_auto_free int16_t *data = NULL;
char *test_suffix;
/* Check several locations for the dist file */
@@ -940,9 +936,12 @@ int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist
if (f == NULL)
return -nl_syserr2nlerr(errno);
- data = (int16_t *) calloc (MAXDIST, sizeof(int16_t));
-
- line = (char *) calloc (sizeof(char), len + 1);
+ data = (int16_t *) calloc(MAXDIST, sizeof(int16_t));
+ line = (char *) calloc(sizeof(char), len + 1);
+ if (!data || !line) {
+ fclose(f);
+ return -NLE_NOMEM;
+ }
while (getline(&line, &len, f) != -1) {
char *p, *endp;
@@ -955,7 +954,6 @@ int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist
if (endp == p) break;
if (n >= MAXDIST) {
- free(line);
fclose(f);
return -NLE_INVAL;
}
@@ -963,11 +961,8 @@ int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist
}
}
- free(line);
fclose(f);
-
i = rtnl_netem_set_delay_distribution_data(qdisc, data, n);
- free(data);
return i;
}
diff --git a/lib/route/qdisc/plug.c b/lib/route/qdisc/plug.c
index 9f536375..38c1c1aa 100644
--- a/lib/route/qdisc/plug.c
+++ b/lib/route/qdisc/plug.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/plug.c PLUG Qdisc
- *
- * 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) 2012 Shriram Rajagopalan <rshriram@cs.ubc.ca>
*/
diff --git a/lib/route/qdisc/prio.c b/lib/route/qdisc/prio.c
index 5a217294..28242a08 100644
--- a/lib/route/qdisc/prio.c
+++ b/lib/route/qdisc/prio.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/prio.c PRIO Qdisc/Class
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/qdisc/red.c b/lib/route/qdisc/red.c
index f05626eb..ccab9471 100644
--- a/lib/route/qdisc/red.c
+++ b/lib/route/qdisc/red.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/red.c RED Qdisc
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/qdisc/sfq.c b/lib/route/qdisc/sfq.c
index acbb4ef8..f52452e1 100644
--- a/lib/route/qdisc/sfq.c
+++ b/lib/route/qdisc/sfq.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/sfq.c SFQ Qdisc
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/qdisc/tbf.c b/lib/route/qdisc/tbf.c
index 23cc8454..ba8e304e 100644
--- a/lib/route/qdisc/tbf.c
+++ b/lib/route/qdisc/tbf.c
@@ -1,11 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/qdisc/tbf.c TBF Qdisc
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
@@ -121,9 +115,9 @@ static void tbf_dump_details(struct rtnl_tc *tc, void *data,
cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
&clu);
- nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) "
- "bucket-size %.1f%s cell-size %.1f%s"
- "latency %.1f%s",
+ nl_dump_line(p,
+ " peak-rate %.2f%s/s (%.0f%s) "
+ "bucket-size %.1f%s cell-size %.1f%s",
pr, pru, prb, prbu, bs, bsu, cl, clu);
}
}
diff --git a/lib/route/route.c b/lib/route/route.c
index 0900b774..fcc7459c 100644
--- a/lib/route/route.c
+++ b/lib/route/route.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/route.c Routes
- *
- * 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-2008 Thomas Graf <tgraf@suug.ch>
*/
@@ -18,6 +11,7 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/nl-auto.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
@@ -131,6 +125,32 @@ int rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags,
result);
}
+int rtnl_route_lookup(struct nl_sock *sk, struct nl_addr *dst,
+ struct rtnl_route **result)
+{
+ _nl_auto_nl_msg struct nl_msg *msg = NULL;
+ _nl_auto_rtnl_route struct rtnl_route *tmpl = NULL;
+ struct nl_object *obj;
+ int err;
+
+ tmpl = rtnl_route_alloc();
+ rtnl_route_set_dst(tmpl, dst);
+ err = build_route_msg(tmpl, RTM_GETROUTE, 0, &msg);
+ if (err < 0)
+ return err;
+
+ err = nl_send_auto(sk, msg);
+ if (err < 0)
+ return err;
+
+ if ((err = nl_pickup(sk, route_msg_parser, &obj)) < 0)
+ return err;
+
+ *result = (struct rtnl_route *)obj;
+ wait_for_ack(sk);
+ return 0;
+}
+
int rtnl_route_add(struct nl_sock *sk, struct rtnl_route *route, int flags)
{
struct nl_msg *msg;
diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c
index bacabe85..9441b77a 100644
--- a/lib/route/route_obj.c
+++ b/lib/route/route_obj.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/route_obj.c Route Object
- *
- * 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-2008 Thomas Graf <tgraf@suug.ch>
*/
@@ -105,22 +98,27 @@ static int route_clone(struct nl_object *_dst, struct nl_object *_src)
struct rtnl_route *src = (struct rtnl_route *) _src;
struct rtnl_nexthop *nh, *new;
- if (src->rt_dst)
+ dst->rt_dst = NULL;
+ dst->rt_src = NULL;
+ dst->rt_pref_src = NULL;
+ nl_init_list_head(&dst->rt_nexthops);
+ dst->rt_nr_nh = 0;
+
+ if (src->rt_dst) {
if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
return -NLE_NOMEM;
+ }
- if (src->rt_src)
+ if (src->rt_src) {
if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
return -NLE_NOMEM;
+ }
- if (src->rt_pref_src)
+ if (src->rt_pref_src) {
if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
return -NLE_NOMEM;
+ }
- /* Will be inc'ed again while adding the nexthops of the source */
- dst->rt_nr_nh = 0;
-
- nl_init_list_head(&dst->rt_nexthops);
nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
new = rtnl_route_nh_clone(nh);
if (!new)
@@ -211,8 +209,8 @@ static void route_dump_line(struct nl_object *a, struct nl_dump_params *p)
static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
{
+ _nl_auto_nl_cache struct nl_cache *link_cache = NULL;
struct rtnl_route *r = (struct rtnl_route *) a;
- struct nl_cache *link_cache;
char buf[256];
int i;
@@ -282,9 +280,6 @@ static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
r->rt_metrics[i]);
nl_dump(p, "]\n");
}
-
- if (link_cache)
- nl_cache_put(link_cache);
}
static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
@@ -310,13 +305,13 @@ static void route_keygen(struct nl_object *obj, uint32_t *hashkey,
struct rtnl_route *route = (struct rtnl_route *) obj;
unsigned int rkey_sz;
struct nl_addr *addr = NULL;
- struct route_hash_key {
+ _nl_auto_free struct route_hash_key {
uint8_t rt_family;
uint8_t rt_tos;
uint32_t rt_table;
uint32_t rt_prio;
char rt_addr[0];
- } __attribute__((packed)) *rkey;
+ } __attribute__((packed)) *rkey = NULL;
#ifdef NL_DEBUG
char buf[INET6_ADDRSTRLEN+5];
#endif
@@ -348,8 +343,6 @@ static void route_keygen(struct nl_object *obj, uint32_t *hashkey,
rkey->rt_table, nl_addr2str(addr, buf, sizeof(buf)),
rkey_sz, *hashkey);
- free(rkey);
-
return;
}
@@ -512,6 +505,16 @@ static int route_update(struct nl_object *old_obj, struct nl_object *new_obj)
switch(action) {
case RTM_NEWROUTE : {
struct rtnl_nexthop *cloned_nh;
+ struct rtnl_nexthop *old_nh;
+
+ /*
+ * Do not add the nexthop to old route if it was already added before
+ */
+ nl_list_for_each_entry(old_nh, &old_route->rt_nexthops, rtnh_list) {
+ if (!rtnl_route_nh_compare(old_nh, new_nh, ~0, 0)) {
+ return 0;
+ }
+ }
/*
* Add the nexthop to old route
@@ -1022,12 +1025,13 @@ static struct nla_policy route_policy[RTA_MAX+1] = {
static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
{
- struct rtnl_nexthop *nh = NULL;
struct rtnexthop *rtnh = nla_data(attr);
size_t tlen = nla_len(attr);
int err;
while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
+ _nl_auto_rtnl_nexthop struct rtnl_nexthop *nh = NULL;
+
nh = rtnl_route_nh_alloc();
if (!nh)
return -NLE_NOMEM;
@@ -1044,20 +1048,17 @@ static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
rtnh->rtnh_len - sizeof(*rtnh),
route_policy);
if (err < 0)
- goto errout;
+ return err;
if (ntb[RTA_GATEWAY]) {
- struct nl_addr *addr;
+ _nl_auto_nl_addr struct nl_addr *addr = NULL;
addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY],
route->rt_family);
- if (!addr) {
- err = -NLE_NOMEM;
- goto errout;
- }
+ if (!addr)
+ return -NLE_NOMEM;
rtnl_route_nh_set_gateway(nh, addr);
- nl_addr_put(addr);
}
if (ntb[RTA_FLOW]) {
@@ -1068,72 +1069,67 @@ static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
}
if (ntb[RTA_NEWDST]) {
- struct nl_addr *addr;
+ _nl_auto_nl_addr struct nl_addr *addr = NULL;
addr = nl_addr_alloc_attr(ntb[RTA_NEWDST],
route->rt_family);
if (!addr)
- goto errout;
+ return -NLE_NOMEM;
err = rtnl_route_nh_set_newdst(nh, addr);
- nl_addr_put(addr);
- if (err)
- goto errout;
+ if (err < 0)
+ return err;
}
if (ntb[RTA_VIA]) {
- struct nl_addr *addr;
+ _nl_auto_nl_addr struct nl_addr *addr = NULL;
addr = rtnl_route_parse_via(ntb[RTA_VIA]);
if (!addr)
- goto errout;
+ return -NLE_NOMEM;
err = rtnl_route_nh_set_via(nh, addr);
- nl_addr_put(addr);
- if (err)
- goto errout;
+ if (err < 0)
+ return err;
}
if (ntb[RTA_ENCAP] && ntb[RTA_ENCAP_TYPE]) {
err = nh_encap_parse_msg(ntb[RTA_ENCAP],
ntb[RTA_ENCAP_TYPE],
nh);
- if (err)
- goto errout;
+ if (err < 0)
+ return err;
}
}
- rtnl_route_add_nexthop(route, nh);
+ rtnl_route_add_nexthop(route, _nl_steal_pointer(&nh));
tlen -= RTNH_ALIGN(rtnh->rtnh_len);
rtnh = RTNH_NEXT(rtnh);
}
- err = 0;
-errout:
- if (err && nh)
- rtnl_route_nh_free(nh);
-
- return err;
+ return 0;
}
int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
{
- struct rtmsg *rtm;
- struct rtnl_route *route;
+ _nl_auto_rtnl_route struct rtnl_route *route = NULL;
+ _nl_auto_rtnl_nexthop struct rtnl_nexthop *old_nh = NULL;
+ _nl_auto_nl_addr struct nl_addr *src = NULL;
+ _nl_auto_nl_addr struct nl_addr *dst = NULL;
struct nlattr *tb[RTA_MAX + 1];
- struct nl_addr *src = NULL, *dst = NULL, *addr;
- struct rtnl_nexthop *old_nh = NULL;
- int err, family;
+ struct rtmsg *rtm;
+ int family;
+ int err;
route = rtnl_route_alloc();
if (!route)
- goto errout_nomem;
+ return -NLE_NOMEM;
route->ce_msgtype = nlh->nlmsg_type;
err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy);
if (err < 0)
- goto errout;
+ return err;
rtm = nlmsg_data(nlh);
route->rt_family = family = rtm->rtm_family;
@@ -1158,31 +1154,28 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
if (tb[RTA_DST]) {
if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
- goto errout_nomem;
+ return -NLE_NOMEM;
} else {
if (!(dst = nl_addr_alloc(0)))
- goto errout_nomem;
+ return -NLE_NOMEM;
nl_addr_set_family(dst, rtm->rtm_family);
}
nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
err = rtnl_route_set_dst(route, dst);
if (err < 0)
- goto errout;
-
- nl_addr_put(dst);
+ return err;
if (tb[RTA_SRC]) {
if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
- goto errout_nomem;
+ return -NLE_NOMEM;
} else if (rtm->rtm_src_len)
if (!(src = nl_addr_alloc(0)))
- goto errout_nomem;
+ return -NLE_NOMEM;
if (src) {
nl_addr_set_prefixlen(src, rtm->rtm_src_len);
rtnl_route_set_src(route, src);
- nl_addr_put(src);
}
if (tb[RTA_TABLE])
@@ -1195,10 +1188,11 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY]));
if (tb[RTA_PREFSRC]) {
+ _nl_auto_nl_addr struct nl_addr *addr = NULL;
+
if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family)))
- goto errout_nomem;
+ return -NLE_NOMEM;
rtnl_route_set_pref_src(route, addr);
- nl_addr_put(addr);
}
if (tb[RTA_METRICS]) {
@@ -1207,7 +1201,7 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
if (err < 0)
- goto errout;
+ return err;
for (i = 1; i <= RTAX_MAX; i++) {
if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
@@ -1215,14 +1209,15 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
err = rtnl_route_set_metric(route, i, m);
if (err < 0)
- goto errout;
+ return err;
}
}
}
- if (tb[RTA_MULTIPATH])
+ if (tb[RTA_MULTIPATH]) {
if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0)
- goto errout;
+ return err;
+ }
if (tb[RTA_CACHEINFO]) {
nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO],
@@ -1232,60 +1227,60 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
if (tb[RTA_OIF]) {
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout_nomem;
+ return -NLE_NOMEM;
rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
}
if (tb[RTA_GATEWAY]) {
+ _nl_auto_nl_addr struct nl_addr *addr = NULL;
+
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout_nomem;
+ return -NLE_NOMEM;
if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
- goto errout_nomem;
+ return -NLE_NOMEM;
rtnl_route_nh_set_gateway(old_nh, addr);
- nl_addr_put(addr);
}
if (tb[RTA_FLOW]) {
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout_nomem;
+ return -NLE_NOMEM;
rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
}
if (tb[RTA_NEWDST]) {
- struct nl_addr *addr;
+ _nl_auto_nl_addr struct nl_addr *addr = NULL;
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout_nomem;
+ return -NLE_NOMEM;
addr = nl_addr_alloc_attr(tb[RTA_NEWDST], route->rt_family);
if (!addr)
- goto errout_nomem;
+ return -NLE_NOMEM;
err = rtnl_route_nh_set_newdst(old_nh, addr);
- nl_addr_put(addr);
- if (err)
- goto errout;
+ if (err < 0)
+ return err;
}
if (tb[RTA_VIA]) {
int alen = nla_len(tb[RTA_VIA]) - offsetof(struct rtvia, rtvia_addr);
+ _nl_auto_nl_addr struct nl_addr *addr = NULL;
struct rtvia *via = nla_data(tb[RTA_VIA]);
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout_nomem;
+ return -NLE_NOMEM;
addr = nl_addr_build(via->rtvia_family, via->rtvia_addr, alen);
if (!addr)
- goto errout_nomem;
+ return -NLE_NOMEM;
err = rtnl_route_nh_set_via(old_nh, addr);
- nl_addr_put(addr);
- if (err)
- goto errout;
+ if (err < 0)
+ return err;
}
if (tb[RTA_TTL_PROPAGATE]) {
@@ -1295,12 +1290,12 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]) {
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout_nomem;
+ return -NLE_NOMEM;
err = nh_encap_parse_msg(tb[RTA_ENCAP],
tb[RTA_ENCAP_TYPE], old_nh);
- if (err)
- goto errout;
+ if (err < 0)
+ return err;
}
if (old_nh) {
@@ -1309,7 +1304,7 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
/* If no nexthops have been provided via RTA_MULTIPATH
* we add it as regular nexthop to maintain backwards
* compatibility */
- rtnl_route_add_nexthop(route, old_nh);
+ rtnl_route_add_nexthop(route, _nl_steal_pointer(&old_nh));
} else {
/* Kernel supports new style nexthop configuration,
* verify that it is a duplicate and discard nexthop. */
@@ -1323,27 +1318,13 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
if (rtnl_route_nh_compare(old_nh, first,
old_nh->ce_mask, 0)) {
- err = -NLE_INVAL;
- goto errout;
+ return -NLE_INVAL;
}
-
- rtnl_route_nh_free(old_nh);
}
- old_nh = NULL;
}
- *result = route;
+ *result = _nl_steal_pointer(&route);
return 0;
-
-errout:
- if (old_nh)
- rtnl_route_nh_free(old_nh);
- rtnl_route_put(route);
- return err;
-
-errout_nomem:
- err = -NLE_NOMEM;
- goto errout;
}
int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
diff --git a/lib/route/route_utils.c b/lib/route/route_utils.c
index 6337f72a..2a196f22 100644
--- a/lib/route/route_utils.c
+++ b/lib/route/route_utils.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/route_utils.c Routing Utilities
- *
- * 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-2006 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/rtnl.c b/lib/route/rtnl.c
index f280a489..f28ebf36 100644
--- a/lib/route/rtnl.c
+++ b/lib/route/rtnl.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/rtnl.c Routing Netlink
- *
- * 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-2012 Thomas Graf <tgraf@suug.ch>
*/
diff --git a/lib/route/rule.c b/lib/route/rule.c
index a0ba42ea..b3a60e14 100644
--- a/lib/route/rule.c
+++ b/lib/route/rule.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/rule.c Routing Rules
- *
- * 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-2010 Thomas Graf <tgraf@suug.ch>
*/
@@ -66,6 +59,9 @@ static int rule_clone(struct nl_object *_dst, struct nl_object *_src)
struct rtnl_rule *dst = nl_object_priv(_dst);
struct rtnl_rule *src = nl_object_priv(_src);
+ dst->r_src = NULL;
+ dst->r_dst = NULL;
+
if (src->r_src)
if (!(dst->r_src = nl_addr_clone(src->r_src)))
return -NLE_NOMEM;
diff --git a/lib/route/tc.c b/lib/route/tc.c
index 35303f59..a06a4789 100644
--- a/lib/route/tc.c
+++ b/lib/route/tc.c
@@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * lib/route/tc.c Traffic Control
- *
- * 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-2011 Thomas Graf <tgraf@suug.ch>
*/
@@ -536,7 +529,7 @@ int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
|| strlen (kind) >= sizeof (tc->tc_kind))
return -NLE_INVAL;
- _nl_strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind));
+ _nl_strncpy_assert(tc->tc_kind, kind, sizeof(tc->tc_kind));
tc->ce_mask |= TCA_ATTR_KIND;
@@ -815,14 +808,17 @@ int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj)
struct rtnl_tc *src = TC_CAST(srcobj);
struct rtnl_tc_ops *ops;
+ dst->tc_opts = NULL;
+ dst->tc_xstats = NULL;
+ dst->tc_subdata = NULL;
+ dst->tc_link = NULL;
+ dst->tc_ops = NULL;
+
if (src->tc_link) {
nl_object_get(OBJ_CAST(src->tc_link));
dst->tc_link = src->tc_link;
}
- dst->tc_opts = NULL;
- dst->tc_xstats = NULL;
- dst->tc_subdata = NULL;
dst->ce_mask &= ~(TCA_ATTR_OPTS |
TCA_ATTR_XSTATS);
@@ -844,18 +840,19 @@ int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj)
if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) {
return -NLE_NOMEM;
}
- }
-
- ops = rtnl_tc_get_ops(src);
- if (ops && ops->to_clone) {
- void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src);
-
- if (!a)
- return 0;
- else if (!b)
- return -NLE_NOMEM;
- return ops->to_clone(a, b);
+ /* Warning: if the data contains pointer, then at this point, dst->tc_subdata
+ * will alias those pointers.
+ *
+ * ops->to_clone() MUST fix that.
+ *
+ * If the type is actually "struct rtnl_act", then to_clone() must also
+ * fix dangling "a_next" pointer. */
+
+ ops = rtnl_tc_get_ops(src);
+ if (ops && ops->to_clone) {
+ return ops->to_clone(rtnl_tc_data(dst), rtnl_tc_data(src));
+ }
}
return 0;
@@ -952,22 +949,19 @@ void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit);
- nl_dump_line(p,
- " %10.2f %3s %10u %-10u %-10u %-10u %-10u\n",
- res, unit,
- tc->tc_stats[RTNL_TC_PACKETS],
- tc->tc_stats[RTNL_TC_DROPS],
- tc->tc_stats[RTNL_TC_OVERLIMITS],
- tc->tc_stats[RTNL_TC_QLEN],
- tc->tc_stats[RTNL_TC_BACKLOG]);
+ nl_dump_line(
+ p,
+ " %10.2f %3s %10llu %-10llu %-10llu %-10llu %-10llu\n",
+ res, unit, (long long unsigned)tc->tc_stats[RTNL_TC_PACKETS],
+ (long long unsigned)tc->tc_stats[RTNL_TC_DROPS],
+ (long long unsigned)tc->tc_stats[RTNL_TC_OVERLIMITS],
+ (long long unsigned)tc->tc_stats[RTNL_TC_QLEN],
+ (long long unsigned)tc->tc_stats[RTNL_TC_BACKLOG]);
res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit);
- nl_dump_line(p,
- " %10.2f %3s/s %10u/s\n",
- res,
- unit,
- tc->tc_stats[RTNL_TC_RATE_PPS]);
+ nl_dump_line(p, " %10.2f %3s/s %10llu/s\n", res, unit,
+ (long long unsigned)tc->tc_stats[RTNL_TC_RATE_PPS]);
}
uint64_t rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj,