From d629ef03d4b87c44b883ee9d51123eb7728d20ce Mon Sep 17 00:00:00 2001 From: Przemyslaw Czarnota Date: Thu, 11 Apr 2019 12:22:38 +0200 Subject: [01/17] route: add gem, pmapper and tcont netdevices --- Makefile.am | 6 + include/netlink/route/link/gem.h | 29 +++ include/netlink/route/link/pmapper.h | 27 +++ include/netlink/route/link/tcont.h | 27 +++ lib/route/link/gem.c | 345 +++++++++++++++++++++++++++ lib/route/link/pmapper.c | 333 ++++++++++++++++++++++++++ lib/route/link/tcont.c | 294 +++++++++++++++++++++++ libnl-route-3.sym | 20 ++ 8 files changed, 1081 insertions(+) create mode 100644 include/netlink/route/link/gem.h create mode 100644 include/netlink/route/link/pmapper.h create mode 100644 include/netlink/route/link/tcont.h create mode 100644 lib/route/link/gem.c create mode 100644 lib/route/link/pmapper.c create mode 100644 lib/route/link/tcont.c diff --git a/Makefile.am b/Makefile.am index 7747d16..1b8522e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -150,6 +150,9 @@ libnlinclude_netlink_route_link_HEADERS = \ include/netlink/route/link/sriov.h \ include/netlink/route/link/veth.h \ include/netlink/route/link/vlan.h \ + include/netlink/route/link/tcont.h \ + include/netlink/route/link/gem.h \ + include/netlink/route/link/pmapper.h \ include/netlink/route/link/vrf.h \ include/netlink/route/link/vxlan.h libnlinclude_netlink_route_qdiscdir = $(libnlincludedir)/netlink/route/qdisc @@ -384,6 +387,9 @@ lib_libnl_route_3_la_SOURCES = \ lib/route/link/sriov.c \ lib/route/link/veth.c \ lib/route/link/vlan.c \ + lib/route/link/tcont.c \ + lib/route/link/gem.c \ + lib/route/link/pmapper.c \ lib/route/link/vrf.c \ lib/route/link/vxlan.c \ lib/route/neigh.c \ diff --git a/include/netlink/route/link/gem.h b/include/netlink/route/link/gem.h new file mode 100644 index 0000000..2d20d4d --- /dev/null +++ b/include/netlink/route/link/gem.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * + * Copyright (c) 2018 Intel Corporation + * + *****************************************************************************/ + +#ifndef NETLINK_LINK_GEM_H_ +#define NETLINK_LINK_GEM_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct rtnl_link *rtnl_link_gem_alloc(void); +extern int rtnl_link_is_gem(struct rtnl_link *); +extern int rtnl_link_gem_set_id(struct rtnl_link *, uint16_t); +extern int rtnl_link_gem_set_index(struct rtnl_link *, uint16_t); +extern int rtnl_link_gem_set_tcont(struct rtnl_link *, uint32_t); +extern int rtnl_link_gem_get_id(struct rtnl_link *); +extern int rtnl_link_gem_get_index(struct rtnl_link *); +extern int rtnl_link_gem_get_tcont(struct rtnl_link *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/netlink/route/link/pmapper.h b/include/netlink/route/link/pmapper.h new file mode 100644 index 0000000..8351e24 --- /dev/null +++ b/include/netlink/route/link/pmapper.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * + * Copyright (c) 2018 Intel Corporation + * + *****************************************************************************/ + +#ifndef NETLINK_LINK_PMAPPER_H_ +#define NETLINK_LINK_PMAPPER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct rtnl_link *rtnl_link_pmapper_alloc(void); +extern int rtnl_link_is_pmapper(struct rtnl_link *); +extern int rtnl_link_pmapper_set_default_pcp(struct rtnl_link *, uint8_t); +extern int rtnl_link_pmapper_set_pcp_ifindex(struct rtnl_link *, uint8_t, int); +extern int rtnl_link_pmapper_get_default_pcp(struct rtnl_link *); +extern int rtnl_link_pmapper_get_pcp_ifindex(struct rtnl_link *, uint8_t); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/netlink/route/link/tcont.h b/include/netlink/route/link/tcont.h new file mode 100644 index 0000000..7077943 --- /dev/null +++ b/include/netlink/route/link/tcont.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * + * Copyright (c) 2018 Intel Corporation + * + *****************************************************************************/ + +#ifndef NETLINK_LINK_TCONT_H_ +#define NETLINK_LINK_TCONT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct rtnl_link *rtnl_link_tcont_alloc(void); +extern int rtnl_link_is_tcont(struct rtnl_link *); +extern int rtnl_link_tcont_set_id(struct rtnl_link *, uint16_t); +extern int rtnl_link_tcont_set_index(struct rtnl_link *, uint16_t); +extern int rtnl_link_tcont_get_id(struct rtnl_link *); +extern int rtnl_link_tcont_get_index(struct rtnl_link *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib/route/link/gem.c b/lib/route/link/gem.c new file mode 100644 index 0000000..fa13333 --- /dev/null +++ b/lib/route/link/gem.c @@ -0,0 +1,345 @@ +/****************************************************************************** + * + * Copyright (c) 2018 Intel Corporation + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define GEM_HAS_IDX (1<<0) +#define GEM_HAS_ID (1<<1) +#define GEM_HAS_TCONT (1<<2) + +struct gem_info +{ + uint16_t index; + uint16_t id; + uint32_t tcont_if; + uint32_t mask; +}; + +/* The NetLink messages the T-Cont configuration. */ +enum { + IFLA_PON_GEM_UNSPEC, + IFLA_PON_GEM_IDX, + IFLA_PON_GEM_ID, + IFLA_PON_GEM_TCONT, + IFLA_PON_GEM_MAX +}; + +/** @endcond */ + +static struct nla_policy gem_policy[IFLA_PON_GEM_MAX + 1] = { + [IFLA_PON_GEM_IDX] = { .type = NLA_U16 }, + [IFLA_PON_GEM_ID] = { .type = NLA_U32 }, + [IFLA_PON_GEM_TCONT] = { .type = NLA_U32 }, +}; + +static int gem_alloc(struct rtnl_link *link) +{ + struct gem_info *gi; + + if (link->l_info) { + gi = link->l_info; + memset(link->l_info, 0, sizeof(*gi)); + } else { + gi = calloc(1, sizeof(*gi)); + if (gi == NULL) + return -NLE_NOMEM; + + link->l_info = gi; + } + + return 0; +} + +static int gem_parse(struct rtnl_link *link, struct nlattr *data, + struct nlattr *xstats) +{ + struct nlattr *tb[IFLA_PON_GEM_MAX + 1]; + struct gem_info *gi; + int err; + + NL_DBG(3, "Parsing GEM link info\n"); + err = nla_parse_nested(tb, IFLA_PON_GEM_MAX, data, gem_policy); + if (err < 0) + goto errout; + + err = gem_alloc(link); + if (err < 0) + goto errout; + + gi = link->l_info; + + if (tb[IFLA_PON_GEM_IDX]) { + gi->index = nla_get_u32(tb[IFLA_PON_GEM_IDX]); + gi->mask |= GEM_HAS_IDX; + } + + if (tb[IFLA_PON_GEM_ID]) { + gi->id = nla_get_u32(tb[IFLA_PON_GEM_ID]); + gi->mask |= GEM_HAS_ID; + } + + if (tb[IFLA_PON_GEM_TCONT]) { + gi->tcont_if = nla_get_u32(tb[IFLA_PON_GEM_TCONT]); + gi->mask |= GEM_HAS_TCONT; + } + + err = 0; +errout: + return err; +} + +static void gem_free(struct rtnl_link *link) +{ + struct gem_info *gi = link->l_info; + + free(gi); + link->l_info = NULL; +} + +static void gem_dump_line(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct gem_info *gi = link->l_info; + + nl_dump(p, "index %d gem-id %d tcont-id %d", gi->index, gi->id, + gi->tcont_if); +} + +static void gem_dump_details(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct gem_info *gi = link->l_info; + /* TODO: To be extended? */ + + nl_dump(p, "index %d gem-id %d tcont-id %d", gi->index, gi->id, + gi->tcont_if); + nl_dump(p, "\n"); +} + +static int gem_clone(struct rtnl_link *dst, struct rtnl_link *src) +{ + struct gem_info *vdst, *vsrc = src->l_info; + int err; + + dst->l_info = NULL; + err = rtnl_link_set_type(dst, "gem"); + if (err < 0) + return err; + vdst = dst->l_info; + + *vdst = *vsrc; + + return 0; +} + +static int gem_put_attrs(struct nl_msg *msg, struct rtnl_link *link) +{ + struct gem_info *gi = link->l_info; + struct nlattr *data; + + data = nla_nest_start(msg, IFLA_INFO_DATA); + if (!data) + return -NLE_MSGSIZE; + + if (gi->mask & GEM_HAS_IDX) + NLA_PUT_U32(msg, IFLA_PON_GEM_IDX, gi->index); + + if (gi->mask & GEM_HAS_ID) + NLA_PUT_U32(msg, IFLA_PON_GEM_ID, gi->id); + + if (gi->mask & GEM_HAS_TCONT) + NLA_PUT_U32(msg, IFLA_PON_GEM_TCONT, gi->tcont_if); + + nla_nest_end(msg, data); + +nla_put_failure: + + return 0; +} + +static struct rtnl_link_info_ops gem_info_ops = { + .io_name = "gem", + .io_alloc = gem_alloc, + .io_parse = gem_parse, + .io_dump = { + [NL_DUMP_LINE] = gem_dump_line, + [NL_DUMP_DETAILS] = gem_dump_details, + }, + .io_clone = gem_clone, + .io_put_attrs = gem_put_attrs, + .io_free = gem_free, +}; + +/** @cond SKIP */ +#define IS_GEM_LINK_ASSERT(link) \ + do { \ + if ((link)->l_info_ops != &gem_info_ops) { \ + APPBUG("Link is not a gem link. set type \"gem\" first."); \ + return -NLE_OPNOTSUPP; \ + } \ + } while (0) +/** @endcond */ + +/** + * Allocate link object of type GEM + * + * @return Allocated link object or NULL. + */ +struct rtnl_link *rtnl_link_gem_alloc(void) +{ + struct rtnl_link *link; + int err; + + link = rtnl_link_alloc(); + if (!link) + return NULL; + + err = rtnl_link_set_type(link, "gem"); + if (err < 0) { + rtnl_link_put(link); + return NULL; + } + + return link; +} + +/** + * Check if link is a GEM link + * @arg link Link object + * + * @return True if link is a GEM link, otherwise false is returned. + */ +int rtnl_link_is_gem(struct rtnl_link *link) +{ + return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "gem"); +} + +/** +* Set GEM Index +* @arg link Link object +* @arg idx GEM Index +* +* @return 0 on success or a negative error code +*/ +int rtnl_link_gem_set_index(struct rtnl_link *link, uint16_t index) +{ + struct gem_info *gi = link->l_info; + + IS_GEM_LINK_ASSERT(link); + + gi->index = index; + gi->mask |= GEM_HAS_IDX; + + return 0; +} + +/** +* Get GEM Index +* @arg link Link object +* +* @return GEM Index, 0 if not set or a negative error code. +*/ +int rtnl_link_gem_get_index(struct rtnl_link *link) +{ + struct gem_info *gi = link->l_info; + + IS_GEM_LINK_ASSERT(link); + + if (gi->mask & GEM_HAS_IDX) + return gi->index; + else + return 0; +} + +/** + * Set GEM ID + * @arg link Link object + * @arg id GEM ID + * + * @return 0 on success or a negative error code + */ +int rtnl_link_gem_set_id(struct rtnl_link *link, uint16_t id) +{ + struct gem_info *gi = link->l_info; + + IS_GEM_LINK_ASSERT(link); + + gi->id = id; + gi->mask |= GEM_HAS_ID; + + return 0; +} + +/** + * Get GEM ID + * @arg link Link object + * + * @return GEM ID, 0 if not set or a negative error code. + */ +int rtnl_link_gem_get_id(struct rtnl_link *link) +{ + struct gem_info *gi = link->l_info; + + IS_GEM_LINK_ASSERT(link); + + if (gi->mask & GEM_HAS_ID) + return gi->id; + else + return 0; +} + +/** + * Set TCONT ID + * @arg link Link object + * @arg tcont_if TCONT interface index + * + * @return 0 on success or a negative error code + */ +int rtnl_link_gem_set_tcont(struct rtnl_link *link, uint32_t tcont_if) +{ + struct gem_info *gi = link->l_info; + + IS_GEM_LINK_ASSERT(link); + + gi->tcont_if = tcont_if; + gi->mask |= GEM_HAS_TCONT; + + return 0; +} + +/** + * Get TCONT ID + * @arg link Link object + * + * @return TCONT id, 0 if not set or a negative error code. + */ +int rtnl_link_gem_get_tcont(struct rtnl_link *link) +{ + struct gem_info *gi = link->l_info; + + IS_GEM_LINK_ASSERT(link); + + if (gi->mask & GEM_HAS_TCONT) + return gi->tcont_if; + else + return 0; +} + +static void __init gem_init(void) +{ + rtnl_link_register_info(&gem_info_ops); +} + +static void __exit gem_exit(void) +{ + rtnl_link_unregister_info(&gem_info_ops); +} diff --git a/lib/route/link/pmapper.c b/lib/route/link/pmapper.c new file mode 100644 index 0000000..c5a9af9 --- /dev/null +++ b/lib/route/link/pmapper.c @@ -0,0 +1,333 @@ +/****************************************************************************** + * + * Copyright (c) 2018 Intel Corporation + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define PMAPPER_HAS_DEF (1<<0) +#define PMAPPER_HAS_PCP(i) (1 << ((i) + 1)) + +#define PMAPPER_PCP_COUNT 8 + +struct pmapper_info +{ + uint8_t def; + uint32_t pcp[8]; + uint32_t mask; +}; + +/* The NetLink messages the PMapper configuration. */ +enum { + IFLA_PON_PMAPPER_UNSPEC, + IFLA_PON_PMAPPER_PCP_DEF, + IFLA_PON_PMAPPER_PCP_0, + IFLA_PON_PMAPPER_PCP_1, + IFLA_PON_PMAPPER_PCP_2, + IFLA_PON_PMAPPER_PCP_3, + IFLA_PON_PMAPPER_PCP_4, + IFLA_PON_PMAPPER_PCP_5, + IFLA_PON_PMAPPER_PCP_6, + IFLA_PON_PMAPPER_PCP_7, + IFLA_PON_PMAPPER_MAX +}; + +/** @endcond */ + +static struct nla_policy pmapper_policy[IFLA_PON_PMAPPER_MAX + 1] = { + [IFLA_PON_PMAPPER_PCP_DEF] = {.type = NLA_U8}, + [IFLA_PON_PMAPPER_PCP_0] = {.type = NLA_U32}, + [IFLA_PON_PMAPPER_PCP_1] = {.type = NLA_U32}, + [IFLA_PON_PMAPPER_PCP_2] = {.type = NLA_U32}, + [IFLA_PON_PMAPPER_PCP_3] = {.type = NLA_U32}, + [IFLA_PON_PMAPPER_PCP_4] = {.type = NLA_U32}, + [IFLA_PON_PMAPPER_PCP_5] = {.type = NLA_U32}, + [IFLA_PON_PMAPPER_PCP_6] = {.type = NLA_U32}, + [IFLA_PON_PMAPPER_PCP_7] = {.type = NLA_U32}, +}; + +static int pmapper_alloc(struct rtnl_link *link) +{ + struct pmapper_info *pi; + + if (link->l_info) { + pi = link->l_info; + memset(link->l_info, 0, sizeof(*pi)); + } else { + pi = calloc(1, sizeof(*pi)); + if (pi == NULL) + return -NLE_NOMEM; + + link->l_info = pi; + } + + return 0; +} + +static int pmapper_parse(struct rtnl_link *link, struct nlattr *data, + struct nlattr *xstats) +{ + struct nlattr *pb[IFLA_PON_PMAPPER_MAX + 1]; + struct pmapper_info *pi; + int err; + int i; + + NL_DBG(3, "Parsing PMAPPER link info\n"); + + err = nla_parse_nested(pb, IFLA_PON_PMAPPER_MAX, data, pmapper_policy); + if (err < 0) + goto errout; + + err = pmapper_alloc(link); + if (err < 0) + goto errout; + + pi = link->l_info; + + if (pb[IFLA_PON_PMAPPER_PCP_DEF]) { + pi->def = nla_get_u8(pb[IFLA_PON_PMAPPER_PCP_DEF]); + pi->mask |= PMAPPER_HAS_DEF; + } + + for (i = 0; i < PMAPPER_PCP_COUNT; ++i) { + if (pb[IFLA_PON_PMAPPER_PCP_0 + i]) { + pi->pcp[i] = + nla_get_u32(pb[IFLA_PON_PMAPPER_PCP_0 + i]); + pi->mask |= PMAPPER_HAS_PCP(i); + } + } + + err = 0; +errout: + return err; +} + +static void pmapper_free(struct rtnl_link *link) +{ + struct pmapper_info *pi = link->l_info; + + free(pi); + link->l_info = NULL; +} + +static void pmapper_dump_line(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct pmapper_info *pi = link->l_info; + + nl_dump(p, "pmapper-def %d", pi->def); +} + +static void pmapper_dump_details(struct rtnl_link *link, + struct nl_dump_params *p) +{ + struct pmapper_info *pi = link->l_info; + int i = 0; + + nl_dump(p, "pmapper-def %d\n", pi->def); + + for (i = 0; i < PMAPPER_PCP_COUNT; ++i) + if (pi->mask & PMAPPER_HAS_PCP(i)) + nl_dump(p, "pmapper-pcp%d %d\n", i, pi->pcp[i]); +} + +static int pmapper_clone(struct rtnl_link *dst, struct rtnl_link *src) +{ + struct pmapper_info *vdst, *vsrc = src->l_info; + int err; + + dst->l_info = NULL; + err = rtnl_link_set_type(dst, "pmapper"); + if (err < 0) + return err; + vdst = dst->l_info; + + *vdst = *vsrc; + + return 0; +} + +static int pmapper_put_attrs(struct nl_msg *msg, struct rtnl_link *link) +{ + struct pmapper_info *pi = link->l_info; + struct nlattr *data; + int i = 0; + + data = nla_nest_start(msg, IFLA_INFO_DATA); + if (!data) + return -NLE_MSGSIZE; + + if (pi->mask & PMAPPER_HAS_DEF) + NLA_PUT_U8(msg, IFLA_PON_PMAPPER_PCP_DEF, pi->def); + + for (i = 0; i < PMAPPER_PCP_COUNT; ++i) + if (pi->mask & PMAPPER_HAS_PCP(i)) + NLA_PUT_U32(msg, IFLA_PON_PMAPPER_PCP_0 + i, + pi->pcp[i]); + + nla_nest_end(msg, data); + +nla_put_failure: + + return 0; +} + +static struct rtnl_link_info_ops pmapper_info_ops = { + .io_name = "pmapper", + .io_alloc = pmapper_alloc, + .io_parse = pmapper_parse, + .io_dump = { + [NL_DUMP_LINE] = pmapper_dump_line, + [NL_DUMP_DETAILS] = pmapper_dump_details, + }, + .io_clone = pmapper_clone, + .io_put_attrs = pmapper_put_attrs, + .io_free = pmapper_free, +}; + +/** @cond SKIP */ +#define IS_PMAPPER_LINK_ASSERT(link) \ + do { \ + if ((link)->l_info_ops != &pmapper_info_ops) { \ + APPBUG("Link is not a pmapper link. set type \"pmapper\" first."); \ + return -NLE_OPNOTSUPP; \ + } \ + } while (0) +/** @endcond */ + +/** + * Allocate link object of type PMAPPER + * + * @return Allocated link object or NULL. + */ +struct rtnl_link *rtnl_link_pmapper_alloc(void) +{ + struct rtnl_link *link; + int err; + + link = rtnl_link_alloc(); + if (!link) + return NULL; + + err = rtnl_link_set_type(link, "pmapper"); + if (err < 0) { + rtnl_link_put(link); + return NULL; + } + + return link; +} + +/** + * Check if link is a PMAPPER link + * @arg link Link object + * + * @return True if link is a PMAPPER link, otherwise false is returned. + */ +int rtnl_link_is_pmapper(struct rtnl_link *link) +{ + return link->l_info_ops + && !strcmp(link->l_info_ops->io_name, "pmapper"); +} + +/** + * Set PMAPPER default pcp + * @arg link Link object + * @arg pcp Default pcp + * + * @return 0 on success or a negative error code + */ +extern int rtnl_link_pmapper_set_default_pcp(struct rtnl_link *link, + uint8_t pcp) +{ + struct pmapper_info *pi = link->l_info; + + IS_PMAPPER_LINK_ASSERT(link); + + if (pcp >= PMAPPER_PCP_COUNT) + return -NLE_RANGE; + + pi->def = pcp; + pi->mask |= PMAPPER_HAS_DEF; + + return 0; +} + +/** + * Assign a pcp to ifindex + * @arg link Link object + * @arg ifindex Interface index + * @arg pcp Default pcp + * + * @return 0 on success or a negative error code + */ +extern int rtnl_link_pmapper_set_pcp_ifindex(struct rtnl_link *link, + uint8_t pcp, int ifindex) +{ + struct pmapper_info *pi = link->l_info; + + IS_PMAPPER_LINK_ASSERT(link); + + if (pcp >= PMAPPER_PCP_COUNT) + return -NLE_RANGE; + + pi->pcp[pcp] = (uint32_t) ifindex; + pi->mask |= PMAPPER_HAS_PCP(pcp); + + return 0; +} + +/** + * Get PMAPPER Default pcp + * @arg link Link object + * + * @return Default PCP or a negative error code. + */ +extern int rtnl_link_pmapper_get_default_pcp(struct rtnl_link *link) +{ + struct pmapper_info *pi = link->l_info; + + IS_PMAPPER_LINK_ASSERT(link); + + if (pi->mask & PMAPPER_HAS_DEF) + return pi->def; + else + return -NLE_MISSING_ATTR; +} + +/** + * Get PMAPPER PCP + * @arg link Link object + * @arg pcp PCP value + * + * @return Interface index or a negative error code. + */ +int rtnl_link_pmapper_get_pcp_ifindex(struct rtnl_link *link, uint8_t pcp) +{ + struct pmapper_info *pi = link->l_info; + + IS_PMAPPER_LINK_ASSERT(link); + + if (pi->mask & PMAPPER_HAS_PCP(pcp)) + return pi->pcp[pcp]; + else + return -NLE_MISSING_ATTR; +} + +static void __init pmapper_init(void) +{ + rtnl_link_register_info(&pmapper_info_ops); +} + +static void __exit pmapper_exit(void) +{ + rtnl_link_unregister_info(&pmapper_info_ops); +} diff --git a/lib/route/link/tcont.c b/lib/route/link/tcont.c new file mode 100644 index 0000000..1b4a04f --- /dev/null +++ b/lib/route/link/tcont.c @@ -0,0 +1,294 @@ +/****************************************************************************** + * + * Copyright (c) 2018 Intel Corporation + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define TCONT_HAS_IDX (1<<0) +#define TCONT_HAS_ID (1<<1) + +struct tcont_info { + uint16_t index; + uint16_t alloc_id; + uint32_t mask; +}; + +/* The NetLink messages the T-Cont configuration. */ +enum { + IFLA_PON_TCONT_UNSPEC, + IFLA_PON_TCONT_IDX, + IFLA_PON_TCONT_ID, + IFLA_PON_TCONT_MAX +}; + +/** @endcond */ + +static struct nla_policy tcont_policy[IFLA_PON_TCONT_MAX + 1] = { + [IFLA_PON_TCONT_IDX] = {.type = NLA_U16}, + [IFLA_PON_TCONT_ID] = {.type = NLA_U32}, +}; + +static int tcont_alloc(struct rtnl_link *link) +{ + struct tcont_info *ti; + + if (link->l_info) { + ti = link->l_info; + memset(link->l_info, 0, sizeof(*ti)); + } else { + ti = calloc(1, sizeof(*ti)); + if (ti == NULL) + return -NLE_NOMEM; + + link->l_info = ti; + } + + return 0; +} + +static int tcont_parse(struct rtnl_link *link, struct nlattr *data, + struct nlattr *xstats) +{ + struct nlattr *tb[IFLA_PON_TCONT_MAX + 1]; + struct tcont_info *ti; + int err; + + NL_DBG(3, "Parsing TCONT link info\n"); + + err = nla_parse_nested(tb, IFLA_PON_TCONT_MAX, data, tcont_policy); + if (err < 0) + goto errout; + + err = tcont_alloc(link); + if (err < 0) + goto errout; + + ti = link->l_info; + + if (tb[IFLA_PON_TCONT_IDX]) { + ti->index = nla_get_u32(tb[IFLA_PON_TCONT_IDX]); + ti->mask |= TCONT_HAS_IDX; + } + + if (tb[IFLA_PON_TCONT_ID]) { + ti->alloc_id = nla_get_u32(tb[IFLA_PON_TCONT_ID]); + ti->mask |= TCONT_HAS_ID; + } + + err = 0; +errout: + return err; +} + +static void tcont_free(struct rtnl_link *link) +{ + struct tcont_info *ti = link->l_info; + + free(ti); + link->l_info = NULL; +} + +static void tcont_dump_line(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct tcont_info *ti = link->l_info; + + nl_dump(p, "index %d tcont-id %d", ti->index, ti->alloc_id); +} + +static void tcont_dump_details(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct tcont_info *ti = link->l_info; + /* TODO: To be extended? */ + + nl_dump(p, "index %d tcont-id %d", ti->index, ti->alloc_id); + nl_dump(p, "\n"); +} + +static int tcont_clone(struct rtnl_link *dst, struct rtnl_link *src) +{ + struct tcont_info *vdst, *vsrc = src->l_info; + int err; + + dst->l_info = NULL; + err = rtnl_link_set_type(dst, "tcont"); + if (err < 0) + return err; + vdst = dst->l_info; + + *vdst = *vsrc; + + return 0; +} + +static int tcont_put_attrs(struct nl_msg *msg, struct rtnl_link *link) +{ + struct tcont_info *ti = link->l_info; + struct nlattr *data; + + data = nla_nest_start(msg, IFLA_INFO_DATA); + if (!data) + return -NLE_MSGSIZE; + + if (ti->mask & TCONT_HAS_IDX) + NLA_PUT_U16(msg, IFLA_PON_TCONT_IDX, ti->index); + + if (ti->mask & TCONT_HAS_ID) + NLA_PUT_U32(msg, IFLA_PON_TCONT_ID, ti->alloc_id); + + nla_nest_end(msg, data); + +nla_put_failure: + + return 0; +} + +static struct rtnl_link_info_ops tcont_info_ops = { + .io_name = "tcont", + .io_alloc = tcont_alloc, + .io_parse = tcont_parse, + .io_dump = { + [NL_DUMP_LINE] = tcont_dump_line, + [NL_DUMP_DETAILS] = tcont_dump_details, + }, + .io_clone = tcont_clone, + .io_put_attrs = tcont_put_attrs, + .io_free = tcont_free, +}; + +/** @cond SKIP */ +#define IS_TCONT_LINK_ASSERT(link) \ + do { \ + if ((link)->l_info_ops != &tcont_info_ops) { \ + APPBUG("Link is not a tcont link. set type \"tcont\" first."); \ + return -NLE_OPNOTSUPP; \ + } \ + } while (0) +/** @endcond */ + +/** + * Allocate link object of type TCONT + * + * @return Allocated link object or NULL. + */ +struct rtnl_link *rtnl_link_tcont_alloc(void) +{ + struct rtnl_link *link; + int err; + + link = rtnl_link_alloc(); + if (!link) + return NULL; + + err = rtnl_link_set_type(link, "tcont"); + if (err < 0) { + rtnl_link_put(link); + return NULL; + } + + return link; +} + +/** + * Check if link is a TCONT link + * @arg link Link object + * + * @return True if link is a TCONT link, otherwise false is returned. + */ +int rtnl_link_is_tcont(struct rtnl_link *link) +{ + return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "tcont"); +} + +/** +* Set TCONT Index +* @arg link Link Object +* @arg index TCONT Index +* +* @return 0 on success or a negstive error code +*/ +int rtnl_link_tcont_set_index(struct rtnl_link *link, uint16_t index) +{ + struct tcont_info *ti = link->l_info; + + IS_TCONT_LINK_ASSERT(link); + + ti->index = index; + ti->mask |= TCONT_HAS_IDX; + + return 0; +} + +/** +* Get TCONT Index +* @arg link Link Object +* +* @return TCONT index, 0 if not set or a negative error code. +*/ +int rtnl_link_tcont_get_index(struct rtnl_link *link) +{ + struct tcont_info *ti = link->l_info; + + IS_TCONT_LINK_ASSERT(link); + + if (ti->mask & TCONT_HAS_IDX) + return ti->index; + else + return 0; +} + +/** + * Set TCONT ID + * @arg link Link object + * @arg id Allocation ID + * + * @return 0 on success or a negative error code + */ +int rtnl_link_tcont_set_id(struct rtnl_link *link, uint16_t id) +{ + struct tcont_info *ti = link->l_info; + + IS_TCONT_LINK_ASSERT(link); + + ti->alloc_id = id; + ti->mask |= TCONT_HAS_ID; + + return 0; +} + +/** + * Get TCONT ID + * @arg link Link object + * + * @return Allocation id, 0 if not set or a negative error code. + */ +int rtnl_link_tcont_get_id(struct rtnl_link *link) +{ + struct tcont_info *ti = link->l_info; + + IS_TCONT_LINK_ASSERT(link); + + if (ti->mask & TCONT_HAS_ID) + return ti->alloc_id; + else + return 0; +} + +static void __init tcont_init(void) +{ + rtnl_link_register_info(&tcont_info_ops); +} + +static void __exit tcont_exit(void) +{ + rtnl_link_unregister_info(&tcont_info_ops); +} diff --git a/libnl-route-3.sym b/libnl-route-3.sym index e66682a..f48e973 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -280,6 +280,13 @@ global: rtnl_link_enslave_ifindex; rtnl_link_fill_info; rtnl_link_flags2str; + rtnl_link_gem_alloc; + rtnl_link_gem_get_id; + rtnl_link_gem_get_index; + rtnl_link_gem_set_id; + rtnl_link_gem_set_index; + rtnl_link_gem_get_tcont; + rtnl_link_gem_set_tcont; rtnl_link_get; rtnl_link_get_addr; rtnl_link_get_arptype; @@ -387,12 +394,15 @@ global: rtnl_link_ipvti_set_remote; rtnl_link_is_bridge; rtnl_link_is_can; + rtnl_link_is_gem; + rtnl_link_is_pmapper; rtnl_link_is_ip6_tnl; rtnl_link_is_ipgre; rtnl_link_is_ipip; rtnl_link_is_ipvti; rtnl_link_is_macvlan; rtnl_link_is_sit; + rtnl_link_is_tcont; rtnl_link_is_veth; rtnl_link_is_vlan; rtnl_link_is_vxlan; @@ -410,6 +420,11 @@ global: rtnl_link_name2i; rtnl_link_operstate2str; rtnl_link_put; + rtnl_link_pmapper_alloc; + rtnl_link_pmapper_set_default_pcp; + rtnl_link_pmapper_set_pcp_ifindex; + rtnl_link_pmapper_get_default_pcp; + rtnl_link_pmapper_get_pcp_ifindex; rtnl_link_release; rtnl_link_release_ifindex; rtnl_link_set_addr; @@ -462,6 +477,11 @@ global: rtnl_link_str2mode; rtnl_link_str2operstate; rtnl_link_str2stat; + rtnl_link_tcont_alloc; + rtnl_link_tcont_get_id; + rtnl_link_tcont_get_index; + rtnl_link_tcont_set_id; + rtnl_link_tcont_set_index; rtnl_link_unset_flags; rtnl_link_veth_add; rtnl_link_veth_alloc; -- 2.17.1