summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-08-24 18:32:13 (GMT)
committerThomas Haller <thaller@redhat.com>2022-08-24 18:32:13 (GMT)
commitcbafad9ddf24caef5230fef715d34f0539603be0 (patch)
tree52aad83c5f021305747f985b7d47b072faa45c38
parent1f1e8385049026ecb050f75b3aa83a3a09a70169 (diff)
parent9167504d18f0616ed1a1d269993885a11fc54000 (diff)
downloadlibnl-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.am2
-rw-r--r--include/netlink/route/link/bridge_info.h35
-rw-r--r--lib/route/link/bridge_info.c303
-rw-r--r--libnl-route-3.sym10
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;