From 201742c09f35540257c4281e8e5fef89c07aea77 Mon Sep 17 00:00:00 2001 From: "Langer, Thomas" Date: Thu, 21 Jan 2021 18:49:28 +0100 Subject: bridge: Add support for link_info of a bridge And functions to access some new bridge attributes. --- include/linux-private/linux/if_link.h | 2 + lib/route/link/bridge.c | 93 +++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) --- a/include/linux-private/linux/if_link.h +++ b/include/linux-private/linux/if_link.h @@ -284,6 +284,8 @@ enum { IFLA_BR_MCAST_STATS_ENABLED, IFLA_BR_MCAST_IGMP_VERSION, IFLA_BR_MCAST_MLD_VERSION, + IFLA_BR_VLAN_STATS_PER_PORT, + IFLA_BR_MULTI_BOOLOPT, __IFLA_BR_MAX, }; --- a/lib/route/link/bridge.c +++ b/lib/route/link/bridge.c @@ -7,6 +7,7 @@ * of the License. * * Copyright (c) 2010-2013 Thomas Graf + * Copyright (c) 2021 MaxLinear, Inc. */ /** @@ -54,6 +55,11 @@ struct bridge_data struct rtnl_link_bridge_vlan vlan_info; }; +struct bridge_info +{ + uint32_t ce_mask; /* to support attr macros */ +}; + static void set_bit(unsigned nr, uint32_t *addr) { if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX) @@ -123,6 +129,10 @@ static struct nla_policy br_attrs_policy [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, }; +static struct nla_policy bi_attrs_policy[IFLA_BR_MAX+1] = { + +}; + static void check_flag(struct rtnl_link *link, struct nlattr *attrs[], int type, int flag) { @@ -1038,13 +1048,96 @@ static struct rtnl_link_af_ops bridge_op .ao_fill_af_no_nest = 1, }; + +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 = 0; + + NL_DBG(3, "Parsing Bridge link info\n"); + + if ((err = nla_parse_nested(tb, IFLA_BR_MAX, data, bi_attrs_policy)) < 0) + goto errout; + + if ((err = bridge_info_alloc(link)) < 0) + goto errout; + + bi = link->l_info; + +errout: + return err; +} + +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) + goto nla_put_failure; + + nla_nest_end(msg, data); + return 0; + +nla_put_failure: + nla_nest_cancel(msg, data); + return -EMSGSIZE; +} + +static void bridge_info_free(struct rtnl_link *link) +{ + free(link->l_info); + link->l_info = NULL; +} + +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) \ + if ((link)->l_info_ops != &bridge_info_ops) { \ + APPBUG("Link is not a bridge link. set type \"bridge\" first."); \ + return -NLE_OPNOTSUPP; \ + } + static void __init bridge_init(void) { rtnl_link_af_register(&bridge_ops); + rtnl_link_register_info(&bridge_info_ops); } static void __exit bridge_exit(void) { + rtnl_link_unregister_info(&bridge_info_ops); rtnl_link_af_unregister(&bridge_ops); }