diff options
Diffstat (limited to 'lib/route')
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, |