]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
bridge: Support the new bridging attributes
authorThomas Graf <tgraf@suug.ch>
Tue, 5 Feb 2013 21:41:26 +0000 (22:41 +0100)
committerThomas Graf <tgraf@suug.ch>
Thu, 7 Feb 2013 10:39:27 +0000 (11:39 +0100)
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 <tgraf@suug.ch>
include/Makefile.am
include/linux/if_bridge.h [new file with mode: 0644]
include/linux/if_link.h
include/netlink/route/link/bridge.h [new file with mode: 0644]
lib/route/link/bridge.c

index af1c136893742388d171a14a88ff3ec70a56ecec..3488c52aabdd8f1e4e6babc7f1b851d04155a2f9 100644 (file)
@@ -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 (file)
index 0000000..5db2975
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *     Linux ethernet bridge
+ *
+ *     Authors:
+ *     Lennert Buytenhek               <buytenh@gnu.org>
+ *
+ *     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 <linux/types.h>
+
+#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 */
index a753d11dd0e9418bcc2d6f059d976d923836c233..73ee05cf4ecb504fc11f085c9351f04f05c9c063 100644 (file)
@@ -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 <linux/types.h>
 #include <linux/netlink.h>
@@ -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 (file)
index 0000000..5522fc0
--- /dev/null
@@ -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 <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_BRIDGE_H_
+#define NETLINK_LINK_BRIDGE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#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
+
index 52beedd9751a07c1abd95b88c145543e36401fd5..a306c9c07ab1f23bc61da544727ee7131182c2d5 100644 (file)
@@ -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 <tgraf@suug.ch>
+ * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup bridge Bridging
+ *
+ * @details
+ * @{
  */
 
 #include <netlink-private/netlink.h>
 #include <netlink/netlink.h>
 #include <netlink/attr.h>
 #include <netlink/route/rtnl.h>
+#include <netlink/route/link/bridge.h>
 #include <netlink-private/route/link/api.h>
+#include <linux/if_bridge.h>
 
-#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);
 
-       return diff;
+       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;
 }
+/** @endcond */
 
-static const struct nla_policy protinfo_policy = {
-       .type                   = NLA_U8,
-};
+/**
+ * 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;
+}
+
+/**
+ * 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);
 }
+
+/** @} */