diff options
author | Thomas Haller <thaller@redhat.com> | 2022-08-24 18:32:13 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-08-24 18:32:13 (GMT) |
commit | cbafad9ddf24caef5230fef715d34f0539603be0 (patch) | |
tree | 52aad83c5f021305747f985b7d47b072faa45c38 | |
parent | 1f1e8385049026ecb050f75b3aa83a3a09a70169 (diff) | |
parent | 9167504d18f0616ed1a1d269993885a11fc54000 (diff) | |
download | libnl-cbafad9ddf24caef5230fef715d34f0539603be0.zip libnl-cbafad9ddf24caef5230fef715d34f0539603be0.tar.gz libnl-cbafad9ddf24caef5230fef715d34f0539603be0.tar.bz2 |
route/bridge: merge branch 'kacperlud:bridge-Add-support-for-link_info-of-a-bridge'
https://github.com/thom311/libnl/pull/329
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | include/netlink/route/link/bridge_info.h | 35 | ||||
-rw-r--r-- | lib/route/link/bridge_info.c | 303 | ||||
-rw-r--r-- | libnl-route-3.sym | 10 |
4 files changed, 350 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index ef0f82d..0ac63d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -148,6 +148,7 @@ libnlinclude_netlink_route_linkdir = $(libnlincludedir)/netlink/route/link libnlinclude_netlink_route_link_HEADERS = \ include/netlink/route/link/api.h \ include/netlink/route/link/bonding.h \ + include/netlink/route/link/bridge_info.h \ include/netlink/route/link/bridge.h \ include/netlink/route/link/can.h \ include/netlink/route/link/geneve.h \ @@ -404,6 +405,7 @@ lib_libnl_route_3_la_SOURCES = \ lib/route/link.c \ lib/route/link/api.c \ lib/route/link/bonding.c \ + lib/route/link/bridge_info.c \ lib/route/link/bridge.c \ lib/route/link/can.c \ lib/route/link/dummy.c \ diff --git a/include/netlink/route/link/bridge_info.h b/include/netlink/route/link/bridge_info.h new file mode 100644 index 0000000..09689b3 --- /dev/null +++ b/include/netlink/route/link/bridge_info.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/* + * Copyright (c) 2022 MaxLinear, Inc. + */ + +#ifndef NETLINK_LINK_BRIDGE_INFO_H_ +#define NETLINK_LINK_BRIDGE_INFO_H_ + +#include <netlink/netlink.h> +#include <netlink/route/link.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_link_bridge_set_vlan_filtering(struct rtnl_link *link, + uint8_t vlan_filtering); +extern int rtnl_link_bridge_get_vlan_filtering(struct rtnl_link *link, + uint8_t *vlan_filtering); + +extern void rtnl_link_bridge_set_vlan_protocol(struct rtnl_link *link, + uint16_t vlan_protocol); +extern int rtnl_link_bridge_get_vlan_protocol(struct rtnl_link *link, + uint16_t *vlan_protocol); + +extern void rtnl_link_bridge_set_vlan_stats_enabled(struct rtnl_link *link, + uint8_t vlan_stats_enabled); +extern int rtnl_link_bridge_get_vlan_stats_enabled(struct rtnl_link *link, + uint8_t *vlan_stats_enabled); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/route/link/bridge_info.c b/lib/route/link/bridge_info.c new file mode 100644 index 0000000..de7dcda --- /dev/null +++ b/lib/route/link/bridge_info.c @@ -0,0 +1,303 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/* + * Copyright (c) 2022 MaxLinear, Inc. + */ + +/** + * @ingroup link + * @defgroup bridge Bridging + * + * @details + * @{ + */ + +#include <netlink-private/netlink.h> +#include <netlink/route/link/bridge_info.h> +#include <netlink-private/route/link/api.h> + +#define BRIDGE_ATTR_VLAN_FILTERING (1 << 0) +#define BRIDGE_ATTR_VLAN_PROTOCOL (1 << 1) +#define BRIDGE_ATTR_VLAN_STATS_ENABLED (1 << 2) + +struct bridge_info { + uint32_t ce_mask; /* to support attr macros */ + uint16_t b_vlan_protocol; + uint8_t b_vlan_filtering; + uint8_t b_vlan_stats_enabled; +}; + +static const struct nla_policy bi_attrs_policy[IFLA_BR_MAX + 1] = { + [IFLA_BR_VLAN_FILTERING] = { .type = NLA_U8 }, + [IFLA_BR_VLAN_PROTOCOL] = { .type = NLA_U16 }, + [IFLA_BR_VLAN_STATS_ENABLED] = { .type = NLA_U8 }, +}; + +static inline struct bridge_info *bridge_info(struct rtnl_link *link) +{ + return link->l_info; +} + +static int bridge_info_alloc(struct rtnl_link *link) +{ + struct bridge_info *bi; + + if (link->l_info) + memset(link->l_info, 0, sizeof(*bi)); + else { + bi = calloc(1, sizeof(*bi)); + if (!bi) + return -NLE_NOMEM; + + link->l_info = bi; + } + + return 0; +} + +static int bridge_info_parse(struct rtnl_link *link, struct nlattr *data, + struct nlattr *xstats) +{ + struct nlattr *tb[IFLA_BR_MAX + 1]; + struct bridge_info *bi; + int err; + + NL_DBG(3, "Parsing Bridge link info\n"); + + if ((err = nla_parse_nested(tb, IFLA_BR_MAX, data, bi_attrs_policy)) < + 0) + return err; + + if ((err = bridge_info_alloc(link)) < 0) + return err; + + bi = link->l_info; + + if (tb[IFLA_BR_VLAN_FILTERING]) { + bi->b_vlan_filtering = nla_get_u8(tb[IFLA_BR_VLAN_FILTERING]); + bi->ce_mask |= BRIDGE_ATTR_VLAN_FILTERING; + } + + if (tb[IFLA_BR_VLAN_PROTOCOL]) { + bi->b_vlan_protocol = + ntohs(nla_get_u16(tb[IFLA_BR_VLAN_PROTOCOL])); + bi->ce_mask |= BRIDGE_ATTR_VLAN_PROTOCOL; + } + + if (tb[IFLA_BR_VLAN_STATS_ENABLED]) { + bi->b_vlan_stats_enabled = + nla_get_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]); + bi->ce_mask |= BRIDGE_ATTR_VLAN_STATS_ENABLED; + } + + return 0; +} + +static int bridge_info_put_attrs(struct nl_msg *msg, struct rtnl_link *link) +{ + struct bridge_info *bi = link->l_info; + struct nlattr *data; + + data = nla_nest_start(msg, IFLA_INFO_DATA); + if (!data) + return -NLE_MSGSIZE; + + if (bi->ce_mask & BRIDGE_ATTR_VLAN_FILTERING) + NLA_PUT_U8(msg, IFLA_BR_VLAN_FILTERING, bi->b_vlan_filtering); + + if (bi->ce_mask & BRIDGE_ATTR_VLAN_PROTOCOL) + NLA_PUT_U16(msg, IFLA_BR_VLAN_PROTOCOL, + htons(bi->b_vlan_protocol)); + + if (bi->ce_mask & BRIDGE_ATTR_VLAN_STATS_ENABLED) + NLA_PUT_U8(msg, IFLA_BR_VLAN_STATS_ENABLED, + bi->b_vlan_stats_enabled); + + nla_nest_end(msg, data); + return 0; + +nla_put_failure: + nla_nest_cancel(msg, data); + return -NLE_MSGSIZE; +} + +static void bridge_info_free(struct rtnl_link *link) +{ + _nl_clear_free(&link->l_info); +} + +static struct rtnl_link_info_ops bridge_info_ops = { + .io_name = "bridge", + .io_alloc = bridge_info_alloc, + .io_parse = bridge_info_parse, + .io_put_attrs = bridge_info_put_attrs, + .io_free = bridge_info_free, +}; + +#define IS_BRIDGE_INFO_ASSERT(link) \ + do { \ + if ((link)->l_info_ops != &bridge_info_ops) { \ + APPBUG("Link is not a bridge link. Set type \"bridge\" first."); \ + } \ + } while (0) + +/** + * Set VLAN filtering flag + * @arg link Link object of type bridge + * @arg vlan_filtering VLAN_filtering boolean flag to set. + * + * @see rtnl_link_bridge_get_vlan_filtering() + * + * @return void + */ +void rtnl_link_bridge_set_vlan_filtering(struct rtnl_link *link, + uint8_t vlan_filtering) +{ + struct bridge_info *bi = bridge_info(link); + + IS_BRIDGE_INFO_ASSERT(link); + + bi->b_vlan_filtering = vlan_filtering; + + bi->ce_mask |= BRIDGE_ATTR_VLAN_FILTERING; +} + +/** + * Get VLAN filtering flag + * @arg link Link object of type bridge + * @arg vlan_filtering Output argument. + * + * @see rtnl_link_bridge_set_vlan_filtering() + * + * @return Zero on success, otherwise a negative error code. + * @retval -NLE_NOATTR + * @retval -NLE_INVAL + */ +int rtnl_link_bridge_get_vlan_filtering(struct rtnl_link *link, + uint8_t *vlan_filtering) +{ + struct bridge_info *bi = bridge_info(link); + + IS_BRIDGE_INFO_ASSERT(link); + + if (!(bi->ce_mask & BRIDGE_ATTR_VLAN_FILTERING)) + return -NLE_NOATTR; + + if (!vlan_filtering) + return -NLE_INVAL; + + *vlan_filtering = bi->b_vlan_filtering; + return 0; +} + +/** + * Set VLAN protocol + * @arg link Link object of type bridge + * @arg vlan_protocol VLAN protocol to set. The protocol + * numbers is in host byte order. + * + * @see rtnl_link_bridge_get_vlan_protocol() + * + * @return void + */ +void rtnl_link_bridge_set_vlan_protocol(struct rtnl_link *link, + uint16_t vlan_protocol) +{ + struct bridge_info *bi = bridge_info(link); + + IS_BRIDGE_INFO_ASSERT(link); + + bi->b_vlan_protocol = vlan_protocol; + + bi->ce_mask |= BRIDGE_ATTR_VLAN_PROTOCOL; +} + +/** + * Get VLAN protocol + * @arg link Link object of type bridge + * @arg vlan_protocol Output argument. The protocol number is in host byte order. + * + * @see rtnl_link_bridge_set_vlan_protocol() + * + * @return Zero on success, otherwise a negative error code. + * @retval -NLE_NOATTR + * @retval -NLE_INVAL + */ +int rtnl_link_bridge_get_vlan_protocol(struct rtnl_link *link, + uint16_t *vlan_protocol) +{ + struct bridge_info *bi = bridge_info(link); + + IS_BRIDGE_INFO_ASSERT(link); + + if (!(bi->ce_mask & BRIDGE_ATTR_VLAN_PROTOCOL)) + return -NLE_NOATTR; + + if (!vlan_protocol) + return -NLE_INVAL; + + *vlan_protocol = bi->b_vlan_protocol; + + return 0; +} + +/** + * Set VLAN stats enabled flag + * @arg link Link object of type bridge + * @arg vlan_stats_enabled VLAN stats enabled flag to set + * + * @see rtnl_link_bridge_get_vlan_stats_enabled() + * + * @return void + */ +void rtnl_link_bridge_set_vlan_stats_enabled(struct rtnl_link *link, + uint8_t vlan_stats_enabled) +{ + struct bridge_info *bi = bridge_info(link); + + IS_BRIDGE_INFO_ASSERT(link); + + bi->b_vlan_stats_enabled = vlan_stats_enabled; + + bi->ce_mask |= BRIDGE_ATTR_VLAN_STATS_ENABLED; +} + +/** + * Get VLAN stats enabled flag + * @arg link Link object of type bridge + * @arg vlan_stats_enabled Output argument. + * + * @see rtnl_link_bridge_set_vlan_stats_enabled() + * + * @return Zero on success, otherwise a negative error code. + * @retval -NLE_NOATTR + * @retval -NLE_INVAL + */ +int rtnl_link_bridge_get_vlan_stats_enabled(struct rtnl_link *link, + uint8_t *vlan_stats_enabled) +{ + struct bridge_info *bi = bridge_info(link); + + IS_BRIDGE_INFO_ASSERT(link); + + if (!(bi->ce_mask & BRIDGE_ATTR_VLAN_STATS_ENABLED)) + return -NLE_NOATTR; + + if (!vlan_stats_enabled) + return -NLE_INVAL; + + *vlan_stats_enabled = bi->b_vlan_stats_enabled; + + return 0; +} + +static void __init bridge_info_init(void) +{ + rtnl_link_register_info(&bridge_info_ops); +} + +static void __exit bridge_info_exit(void) +{ + rtnl_link_unregister_info(&bridge_info_ops); +} + +/** @} */ diff --git a/libnl-route-3.sym b/libnl-route-3.sym index b6503b3..5e37acf 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -1274,3 +1274,13 @@ global: rtnl_nat_set_new_addr; rtnl_nat_set_old_addr; } libnl_3_6; + +libnl_3_8 { +global: + rtnl_link_bridge_get_vlan_filtering; + rtnl_link_bridge_get_vlan_protocol; + rtnl_link_bridge_get_vlan_stats_enabled; + rtnl_link_bridge_set_vlan_filtering; + rtnl_link_bridge_set_vlan_protocol; + rtnl_link_bridge_set_vlan_stats_enabled; +} libnl_3_7; |