From fd19dae352d761760bc161a81a98bc14cbe99733 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 5 Feb 2013 22:41:26 +0100 Subject: [PATCH] bridge: Support the new bridging attributes This provides support for the new bridging attributes provided in IFLA_PROTINFO while maintaining backwards compatibility with older kernels. A set of new API functions are exported to access the bridging information. rtnl_link_bridge_has_ext_info() can be used to check whether a bridge object has been constructed based on the newly available attributes or the old message format. Signed-off-by: Thomas Graf --- include/Makefile.am | 2 + include/linux/if_bridge.h | 185 ++++++++++++++ include/linux/if_link.h | 80 ++++-- include/netlink/route/link/bridge.h | 54 ++++ lib/route/link/bridge.c | 374 +++++++++++++++++++++++++++- 5 files changed, 668 insertions(+), 27 deletions(-) create mode 100644 include/linux/if_bridge.h create mode 100644 include/netlink/route/link/bridge.h diff --git a/include/Makefile.am b/include/Makefile.am index af1c136..3488c52 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -42,6 +42,7 @@ nobase_libnlinclude_HEADERS = \ netlink/route/cls/police.h \ netlink/route/cls/u32.h \ netlink/route/link/bonding.h \ + netlink/route/link/bridge.h \ netlink/route/link/can.h \ netlink/route/link/inet.h \ netlink/route/link/vlan.h \ @@ -103,6 +104,7 @@ noinst_HEADERS = \ linux/if_arp.h \ linux/if_ether.h \ linux/if.h \ + linux/if_bridge.h \ linux/if_link.h \ linux/if_vlan.h \ linux/inetdevice.h \ diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h new file mode 100644 index 0000000..5db2975 --- /dev/null +++ b/include/linux/if_bridge.h @@ -0,0 +1,185 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _UAPI_LINUX_IF_BRIDGE_H +#define _UAPI_LINUX_IF_BRIDGE_H + +#include + +#define SYSFS_BRIDGE_ATTR "bridge" +#define SYSFS_BRIDGE_FDB "brforward" +#define SYSFS_BRIDGE_PORT_SUBDIR "brif" +#define SYSFS_BRIDGE_PORT_ATTR "brport" +#define SYSFS_BRIDGE_PORT_LINK "bridge" + +#define BRCTL_VERSION 1 + +#define BRCTL_GET_VERSION 0 +#define BRCTL_GET_BRIDGES 1 +#define BRCTL_ADD_BRIDGE 2 +#define BRCTL_DEL_BRIDGE 3 +#define BRCTL_ADD_IF 4 +#define BRCTL_DEL_IF 5 +#define BRCTL_GET_BRIDGE_INFO 6 +#define BRCTL_GET_PORT_LIST 7 +#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8 +#define BRCTL_SET_BRIDGE_HELLO_TIME 9 +#define BRCTL_SET_BRIDGE_MAX_AGE 10 +#define BRCTL_SET_AGEING_TIME 11 +#define BRCTL_SET_GC_INTERVAL 12 +#define BRCTL_GET_PORT_INFO 13 +#define BRCTL_SET_BRIDGE_STP_STATE 14 +#define BRCTL_SET_BRIDGE_PRIORITY 15 +#define BRCTL_SET_PORT_PRIORITY 16 +#define BRCTL_SET_PATH_COST 17 +#define BRCTL_GET_FDB_ENTRIES 18 + +#define BR_STATE_DISABLED 0 +#define BR_STATE_LISTENING 1 +#define BR_STATE_LEARNING 2 +#define BR_STATE_FORWARDING 3 +#define BR_STATE_BLOCKING 4 + +struct __bridge_info { + __u64 designated_root; + __u64 bridge_id; + __u32 root_path_cost; + __u32 max_age; + __u32 hello_time; + __u32 forward_delay; + __u32 bridge_max_age; + __u32 bridge_hello_time; + __u32 bridge_forward_delay; + __u8 topology_change; + __u8 topology_change_detected; + __u8 root_port; + __u8 stp_enabled; + __u32 ageing_time; + __u32 gc_interval; + __u32 hello_timer_value; + __u32 tcn_timer_value; + __u32 topology_change_timer_value; + __u32 gc_timer_value; +}; + +struct __port_info { + __u64 designated_root; + __u64 designated_bridge; + __u16 port_id; + __u16 designated_port; + __u32 path_cost; + __u32 designated_cost; + __u8 state; + __u8 top_change_ack; + __u8 config_pending; + __u8 unused0; + __u32 message_age_timer_value; + __u32 forward_delay_timer_value; + __u32 hold_timer_value; +}; + +struct __fdb_entry { + __u8 mac_addr[6]; + __u8 port_no; + __u8 is_local; + __u32 ageing_timer_value; + __u8 port_hi; + __u8 pad0; + __u16 unused; +}; + +/* Bridge Flags */ +#define BRIDGE_FLAGS_MASTER 1 /* Bridge command to/from master */ +#define BRIDGE_FLAGS_SELF 2 /* Bridge command to/from lowerdev */ + +#define BRIDGE_MODE_VEB 0 /* Default loopback mode */ +#define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */ + +/* Bridge management nested attributes + * [IFLA_AF_SPEC] = { + * [IFLA_BRIDGE_FLAGS] + * [IFLA_BRIDGE_MODE] + * } + */ +enum { + IFLA_BRIDGE_FLAGS, + IFLA_BRIDGE_MODE, + __IFLA_BRIDGE_MAX, +}; +#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) + +/* Bridge multicast database attributes + * [MDBA_MDB] = { + * [MDBA_MDB_ENTRY] = { + * [MDBA_MDB_ENTRY_INFO] + * } + * } + * [MDBA_ROUTER] = { + * [MDBA_ROUTER_PORT] + * } + */ +enum { + MDBA_UNSPEC, + MDBA_MDB, + MDBA_ROUTER, + __MDBA_MAX, +}; +#define MDBA_MAX (__MDBA_MAX - 1) + +enum { + MDBA_MDB_UNSPEC, + MDBA_MDB_ENTRY, + __MDBA_MDB_MAX, +}; +#define MDBA_MDB_MAX (__MDBA_MDB_MAX - 1) + +enum { + MDBA_MDB_ENTRY_UNSPEC, + MDBA_MDB_ENTRY_INFO, + __MDBA_MDB_ENTRY_MAX, +}; +#define MDBA_MDB_ENTRY_MAX (__MDBA_MDB_ENTRY_MAX - 1) + +enum { + MDBA_ROUTER_UNSPEC, + MDBA_ROUTER_PORT, + __MDBA_ROUTER_MAX, +}; +#define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1) + +struct br_port_msg { + __u8 family; + __u32 ifindex; +}; + +struct br_mdb_entry { + __u32 ifindex; +#define MDB_TEMPORARY 0 +#define MDB_PERMANENT 1 + __u8 state; + struct { + union { + __be32 ip4; + struct in6_addr ip6; + } u; + __be16 proto; + } addr; +}; + +enum { + MDBA_SET_ENTRY_UNSPEC, + MDBA_SET_ENTRY, + __MDBA_SET_ENTRY_MAX, +}; +#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1) + +#endif /* _UAPI_LINUX_IF_BRIDGE_H */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index a753d11..73ee05c 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -1,5 +1,5 @@ -#ifndef _LINUX_IF_LINK_H -#define _LINUX_IF_LINK_H +#ifndef _UAPI_LINUX_IF_LINK_H +#define _UAPI_LINUX_IF_LINK_H #include #include @@ -200,6 +200,24 @@ enum { #define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) +enum { + BRIDGE_MODE_UNSPEC, + BRIDGE_MODE_HAIRPIN, +}; + +enum { + IFLA_BRPORT_UNSPEC, + IFLA_BRPORT_STATE, /* Spanning tree state */ + IFLA_BRPORT_PRIORITY, /* " priority */ + IFLA_BRPORT_COST, /* " cost */ + IFLA_BRPORT_MODE, /* mode (hairpin) */ + IFLA_BRPORT_GUARD, /* bpdu guard */ + IFLA_BRPORT_PROTECT, /* root port protection */ + IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */ + __IFLA_BRPORT_MAX +}; +#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) + struct ifla_cacheinfo { __u32 max_reasm_len; __u32 tstamp; /* ipv6InterfaceTable updated timestamp */ @@ -267,6 +285,32 @@ enum macvlan_mode { #define MACVLAN_FLAG_NOPROMISC 1 +/* VXLAN section */ +enum { + IFLA_VXLAN_UNSPEC, + IFLA_VXLAN_ID, + IFLA_VXLAN_GROUP, + IFLA_VXLAN_LINK, + IFLA_VXLAN_LOCAL, + IFLA_VXLAN_TTL, + IFLA_VXLAN_TOS, + IFLA_VXLAN_LEARNING, + IFLA_VXLAN_AGEING, + IFLA_VXLAN_LIMIT, + IFLA_VXLAN_PORT_RANGE, + IFLA_VXLAN_PROXY, + IFLA_VXLAN_RSC, + IFLA_VXLAN_L2MISS, + IFLA_VXLAN_L3MISS, + __IFLA_VXLAN_MAX +}; +#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) + +struct ifla_vxlan_port_range { + __be16 low; + __be16 high; +}; + /* SR-IOV virtual function management section */ enum { @@ -308,18 +352,6 @@ struct ifla_vf_spoofchk { __u32 vf; __u32 setting; }; -#ifdef __KERNEL__ - -/* We don't want this structure exposed to user space */ -struct ifla_vf_info { - __u32 vf; - __u8 mac[32]; - __u32 vlan; - __u32 qos; - __u32 tx_rate; - __u32 spoofchk; -}; -#endif /* VF ports management section * @@ -393,4 +425,22 @@ struct ifla_port_vsi { __u8 pad[3]; }; -#endif /* _LINUX_IF_LINK_H */ + +/* IPoIB section */ + +enum { + IFLA_IPOIB_UNSPEC, + IFLA_IPOIB_PKEY, + IFLA_IPOIB_MODE, + IFLA_IPOIB_UMCAST, + __IFLA_IPOIB_MAX +}; + +enum { + IPOIB_MODE_DATAGRAM = 0, /* using unreliable datagram QPs */ + IPOIB_MODE_CONNECTED = 1, /* using connected QPs */ +}; + +#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1) + +#endif /* _UAPI_LINUX_IF_LINK_H */ diff --git a/include/netlink/route/link/bridge.h b/include/netlink/route/link/bridge.h new file mode 100644 index 0000000..5522fc0 --- /dev/null +++ b/include/netlink/route/link/bridge.h @@ -0,0 +1,54 @@ +/* + * netlink/route/link/bridge.h Bridge + * + * 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 Thomas Graf + */ + +#ifndef NETLINK_LINK_BRIDGE_H_ +#define NETLINK_LINK_BRIDGE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Bridge flags + * @ingroup bridge + */ +enum rtnl_link_bridge_flags { + RTNL_BRIDGE_HAIRPIN_MODE = 0x0001, + RTNL_BRIDGE_BPDU_GUARD = 0x0002, + RTNL_BRIDGE_ROOT_BLOCK = 0x0004, + RTNL_BRIDGE_FAST_LEAVE = 0x0008, +}; + +extern int rtnl_link_is_bridge(struct rtnl_link *); +extern int rtnl_link_bridge_has_ext_info(struct rtnl_link *); + +extern int rtnl_link_bridge_set_port_state(struct rtnl_link *, uint8_t ); +extern int rtnl_link_bridge_get_port_state(struct rtnl_link *); + +extern int rtnl_link_bridge_set_priority(struct rtnl_link *, uint16_t); +extern int rtnl_link_bridge_get_priority(struct rtnl_link *); + +extern int rtnl_link_bridge_set_cost(struct rtnl_link *, uint32_t); +extern int rtnl_link_bridge_get_cost(struct rtnl_link *, uint32_t *); + +extern int rtnl_link_bridge_unset_flags(struct rtnl_link *, unsigned int); +extern int rtnl_link_bridge_set_flags(struct rtnl_link *, unsigned int); +extern int rtnl_link_bridge_get_flags(struct rtnl_link *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib/route/link/bridge.c b/lib/route/link/bridge.c index 52beedd..a306c9c 100644 --- a/lib/route/link/bridge.c +++ b/lib/route/link/bridge.c @@ -1,28 +1,62 @@ /* - * lib/route/link/bridge.c AF_BRIDGE link oeprations + * 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 Thomas Graf + * Copyright (c) 2010-2013 Thomas Graf + */ + +/** + * @ingroup link + * @defgroup bridge Bridging + * + * @details + * @{ */ #include #include #include #include +#include #include +#include -#define BRIDGE_ATTR_PORT_STATE 0x0001 +/** @cond SKIP */ +#define BRIDGE_ATTR_PORT_STATE (1 << 0) +#define BRIDGE_ATTR_PRIORITY (1 << 1) +#define BRIDGE_ATTR_COST (1 << 2) +#define BRIDGE_ATTR_FLAGS (1 << 3) + +#define PRIV_FLAG_NEW_ATTRS (1 << 0) struct bridge_data { uint8_t b_port_state; + uint8_t b_priv_flags; /* internal flags */ + uint16_t b_priority; + uint32_t b_cost; + uint32_t b_flags; + uint32_t b_flags_mask; uint32_t ce_mask; /* HACK to support attr macros */ }; +static struct rtnl_link_af_ops bridge_ops; + +#define IS_BRIDGE_LINK_ASSERT(link) \ + if (!rtnl_link_is_bridge(link)) { \ + APPBUG("A function was expecting a link object of type bridge."); \ + return -NLE_OPNOTSUPP; \ + } + +static inline struct bridge_data *bridge_data(struct rtnl_link *link) +{ + return rtnl_link_af_data(link, &bridge_ops); +} + static void *bridge_alloc(struct rtnl_link *link) { return calloc(1, sizeof(struct bridge_data)); @@ -43,13 +77,66 @@ static void bridge_free(struct rtnl_link *link, void *data) free(data); } +static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = { + [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, + [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 }, + [IFLA_BRPORT_COST] = { .type = NLA_U32 }, + [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, + [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, + [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, + [IFLA_BRPORT_FAST_LEAVE] = { .type = NLA_U8 }, +}; + +static void check_flag(struct rtnl_link *link, struct nlattr *attrs[], + int type, int flag) +{ + if (attrs[type] && nla_get_u8(attrs[type])) + rtnl_link_bridge_set_flags(link, flag); +} + static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr, void *data) { struct bridge_data *bd = data; + struct nlattr *br_attrs[IFLA_BRPORT_MAX+1]; + int err; - bd->b_port_state = nla_get_u8(attr); - bd->ce_mask |= BRIDGE_ATTR_PORT_STATE; + /* Backwards compatibility */ + if (!nla_is_nested(attr)) { + if (nla_len(attr) < 1) + return -NLE_RANGE; + + bd->b_port_state = nla_get_u8(attr); + bd->ce_mask |= BRIDGE_ATTR_PORT_STATE; + + return 0; + } + + if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr, + br_attrs_policy)) < 0) + return err; + + bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS; + + if (br_attrs[IFLA_BRPORT_STATE]) { + bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]); + bd->ce_mask |= BRIDGE_ATTR_PORT_STATE; + } + + if (br_attrs[IFLA_BRPORT_PRIORITY]) { + bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]); + bd->ce_mask |= BRIDGE_ATTR_PRIORITY; + } + + if (br_attrs[IFLA_BRPORT_COST]) { + bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]); + bd->ce_mask |= BRIDGE_ATTR_COST; + } + + check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE); + check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD); + check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK); + check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE); return 0; } @@ -59,27 +146,289 @@ static void bridge_dump_details(struct rtnl_link *link, { struct bridge_data *bd = data; + nl_dump_line(p, " bridge: "); + if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE) nl_dump(p, "port-state %u ", bd->b_port_state); + + if (bd->ce_mask & BRIDGE_ATTR_PRIORITY) + nl_dump(p, "prio %u ", bd->b_priority); + + if (bd->ce_mask & BRIDGE_ATTR_COST) + nl_dump(p, "cost %u ", bd->b_cost); + + nl_dump(p, "\n"); } static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b, int family, uint32_t attrs, int flags) { - struct bridge_data *a = (struct bridge_data *)_a->l_af_data; - struct bridge_data *b = (struct bridge_data *)_b->l_af_data; + struct bridge_data *a = bridge_data(_a); + struct bridge_data *b = bridge_data(_b); int diff = 0; #define BRIDGE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, BRIDGE_ATTR_##ATTR, a, b, EXPR) diff |= BRIDGE_DIFF(PORT_STATE, a->b_port_state != b->b_port_state); + diff |= BRIDGE_DIFF(PRIORITY, a->b_priority != b->b_priority); + diff |= BRIDGE_DIFF(COST, a->b_cost != b->b_cost); + + if (flags & LOOSE_COMPARISON) + diff |= BRIDGE_DIFF(FLAGS, + (a->b_flags ^ b->b_flags) & b->b_flags_mask); + else + diff |= BRIDGE_DIFF(FLAGS, a->b_flags != b->b_flags); +#undef BRIDGE_DIFF return diff; -#undef BRIDGE_DIFF +} +/** @endcond */ + +/** + * Check if a link is a bridge + * @arg link Link object + * + * @return 1 if the link is a bridge, 0 otherwise. + */ +int rtnl_link_is_bridge(struct rtnl_link *link) +{ + return link->l_family == AF_BRIDGE && + link->l_af_ops == &bridge_ops; } -static const struct nla_policy protinfo_policy = { - .type = NLA_U8, -}; +/** + * Check if bridge has extended information + * @arg link Link object of type bridge + * + * Checks if the bridge object has been constructed based on + * information that is only available in newer kernels. This + * affectes the following functions: + * - rtnl_link_bridge_get_cost() + * - rtnl_link_bridge_get_priority() + * - rtnl_link_bridge_get_flags() + * + * @return 1 if extended information is available, otherwise 0 is returned. + */ +int rtnl_link_bridge_has_ext_info(struct rtnl_link *link) +{ + struct bridge_data *bd; + + if (!rtnl_link_is_bridge(link)) + return 0; + + bd = bridge_data(link); + return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS); +} + +/** + * Set Spanning Tree Protocol (STP) port state + * @arg link Link object of type bridge + * @arg state New STP port state + * + * The value of state must be one of the following: + * - BR_STATE_DISABLED + * - BR_STATE_LISTENING + * - BR_STATE_LEARNING + * - BR_STATE_FORWARDING + * - BR_STATE_BLOCKING + * + * @see rtnl_link_bridge_get_port_state() + * + * @return 0 on success or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING) + */ +int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + if (state > BR_STATE_BLOCKING) + return -NLE_INVAL; + + bd->b_port_state = state; + bd->ce_mask |= BRIDGE_ATTR_PORT_STATE; + + return 0; +} + +/** + * Get Spanning Tree Protocol (STP) port state + * @arg link Link object of type bridge + * + * @see rtnl_link_bridge_set_port_state() + * + * @return The STP port state or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + */ +int rtnl_link_bridge_get_port_state(struct rtnl_link *link) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + return bd->b_port_state; +} + +/** + * Set priority + * @arg link Link object of type bridge + * @arg prio Bridge priority + * + * @see rtnl_link_bridge_get_priority() + * + * @return 0 on success or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + */ +int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + bd->b_priority = prio; + bd->ce_mask |= BRIDGE_ATTR_PRIORITY; + + return 0; +} + +/** + * Get priority + * @arg link Link object of type bridge + * + * @see rtnl_link_bridge_set_priority() + * + * @return 0 on success or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + */ +int rtnl_link_bridge_get_priority(struct rtnl_link *link) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + return bd->b_priority; +} + +/** + * Set Spanning Tree Protocol (STP) path cost + * @arg link Link object of type bridge + * @arg cost New STP path cost value + * + * @see rtnl_link_bridge_get_cost() + * + * @return The bridge priority or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + */ +int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + bd->b_cost = cost; + bd->ce_mask |= BRIDGE_ATTR_COST; + + return 0; +} + +/** + * Get Spanning Tree Protocol (STP) path cost + * @arg link Link object of type bridge + * @arg cost Pointer to store STP cost value + * + * @see rtnl_link_bridge_set_cost() + * + * @return 0 on success or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + * @retval -NLE_INVAL `cost` is not a valid pointer + */ +int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + if (!cost) + return -NLE_INVAL; + + *cost = bd->b_cost; + + return 0; +} + +/** + * Unset flags + * @arg link Link object of type bridge + * @arg flags Bridging flags to unset + * + * @see rtnl_link_bridge_set_flags() + * @see rtnl_link_bridge_get_flags() + * + * @return 0 on success or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + */ +int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + bd->b_flags_mask |= flags; + bd->b_flags &= ~flags; + bd->ce_mask |= BRIDGE_ATTR_FLAGS; + + return 0; +} + +/** + * Set flags + * @arg link Link object of type bridge + * @arg flags Bridging flags to set + * + * Valid flags are: + * - RTNL_BRIDGE_HAIRPIN_MODE + * - RTNL_BRIDGE_BPDU_GUARD + * - RTNL_BRIDGE_ROOT_BLOCK + * - RTNL_BRIDGE_FAST_LEAVE + * + * @see rtnl_link_bridge_unset_flags() + * @see rtnl_link_bridge_get_flags() + * + * @return 0 on success or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + */ +int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + bd->b_flags_mask |= flags; + bd->b_flags |= flags; + bd->ce_mask |= BRIDGE_ATTR_FLAGS; + + return 0; +} + +/** + * Get flags + * @arg link Link object of type bridge + * + * @see rtnl_link_bridge_set_flags() + * @see rtnl_link_bridge_unset_flags() + * + * @return Flags or a negative error code. + * @retval -NLE_OPNOTSUPP Link is not a bridge + */ +int rtnl_link_bridge_get_flags(struct rtnl_link *link) +{ + struct bridge_data *bd = bridge_data(link); + + IS_BRIDGE_LINK_ASSERT(link); + + return bd->b_flags; +} static struct rtnl_link_af_ops bridge_ops = { .ao_family = AF_BRIDGE, @@ -88,7 +437,6 @@ static struct rtnl_link_af_ops bridge_ops = { .ao_free = &bridge_free, .ao_parse_protinfo = &bridge_parse_protinfo, .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details, - .ao_protinfo_policy = &protinfo_policy, .ao_compare = &bridge_compare, }; @@ -101,3 +449,5 @@ static void __exit bridge_exit(void) { rtnl_link_af_unregister(&bridge_ops); } + +/** @} */