Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132983243
D51238.id158304.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D51238.id158304.diff
View Options
diff --git a/sbin/ifconfig/ifbridge.c b/sbin/ifconfig/ifbridge.c
--- a/sbin/ifconfig/ifbridge.c
+++ b/sbin/ifconfig/ifbridge.c
@@ -48,6 +48,9 @@
#include <net/if_bridgevar.h>
#include <net/route.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_generic.h>
+
#include <ctype.h>
#include <stdio.h>
#include <string.h>
@@ -273,26 +276,81 @@
ifconfig_bridge_free_bridge_status(bridge);
}
+static struct nlmsghdr *
+bridge_init_netlink(struct snl_state *ss, struct snl_writer *nw, if_ctx *ctx,
+ int request)
+{
+ struct nlmsghdr *hdr;
+ int family_id;
+
+ if (!snl_init(ss, NETLINK_GENERIC))
+ errx(1, "snl_init() failed (netlink not supported?)");
+
+ snl_init_writer(ss, nw);
+
+ family_id = snl_get_genl_family(ss, BRIDGE_NL_FAMILY_NAME);
+ if (family_id == 0)
+ errx(1, "bridge netlink family not supported");
+
+ hdr = snl_create_genl_msg_request(nw, family_id, request);
+ snl_add_msg_attr_string(nw, BRIDGE_NL_BRIDGE, ctx->ifname);
+
+ return (hdr);
+}
+
+static void
+bridge_send_netlink(struct snl_state *ss, struct snl_writer *nw,
+ struct nlmsghdr *hdr)
+{
+ struct snl_errmsg_data e = { };
+ uint32_t seq_id;
+
+ hdr = snl_finalize_msg(nw);
+ if (hdr == NULL)
+ errx(1, "failed to finalise the netlink message");
+
+ seq_id = hdr->nlmsg_seq;
+ if (!snl_send_message(ss, hdr))
+ errx(1, "failed to send the netlink message");
+
+ if (!snl_read_reply_code(ss, seq_id, &e)) {
+ if (e.error_str != NULL)
+ errx(1, "%s", e.error_str);
+ else if (e.error != 0)
+ errc(1, e.error, NULL);
+ else
+ errx(1, "failed to read netlink reply");
+ }
+
+ snl_free(ss);
+}
+
static void
setbridge_add(if_ctx *ctx, const char *val, int dummy __unused)
{
- struct ifbreq req;
+ struct snl_state ss = {};
+ struct snl_writer nw;
+ struct nlmsghdr *hdr;
- memset(&req, 0, sizeof(req));
- strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
- if (do_cmd(ctx, BRDGADD, &req, sizeof(req), 1) < 0)
- err(1, "BRDGADD %s", val);
+ hdr = bridge_init_netlink(&ss, &nw, ctx, BRIDGE_NL_CMD_ADDMEMBER);
+
+ snl_add_msg_attr_string(&nw, BRIDGE_NL_MEMBER, val);
+
+ bridge_send_netlink(&ss, &nw, hdr);
}
static void
setbridge_delete(if_ctx *ctx, const char *val, int dummy __unused)
{
- struct ifbreq req;
+ struct snl_state ss = {};
+ struct snl_writer nw;
+ struct nlmsghdr *hdr;
- memset(&req, 0, sizeof(req));
- strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
- if (do_cmd(ctx, BRDGDEL, &req, sizeof(req), 1) < 0)
- err(1, "BRDGDEL %s", val);
+ hdr = bridge_init_netlink(&ss, &nw, ctx, BRIDGE_NL_CMD_REMOVEMEMBER);
+
+ snl_add_msg_attr_string(&nw, BRIDGE_NL_MEMBER, val);
+
+ bridge_send_netlink(&ss, &nw, hdr);
}
static void
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -132,6 +132,16 @@
#include <net/if_llc.h>
#include <net/if_vlan_var.h>
+#include <netlink/netlink.h>
+#include <netlink/netlink_ctl.h>
+#include <netlink/netlink_generic.h>
+#include <netlink/netlink_message_writer.h>
+
+#define DEBUG_MOD_NAME nl_bridge
+#define DEBUG_MAX_LEVEL LOG_DEBUG3
+#include <netlink/netlink_debug.h>
+_DECLARE_DEBUG(LOG_DEBUG);
+
#include <net/route.h>
#define EXTERR_CATEGORY EXTERR_CAT_BRIDGE
@@ -386,6 +396,9 @@
static void bridge_delete_span(struct bridge_softc *,
struct bridge_iflist *);
+static void bridge_cmd_add(struct bridge_softc *sc, struct ifnet *ifs,
+ int *error, char const **errmsg);
+
static int bridge_ioctl_add(struct bridge_softc *, void *);
static int bridge_ioctl_del(struct bridge_softc *, void *);
static int bridge_ioctl_gifflags(struct bridge_softc *, void *);
@@ -437,6 +450,9 @@
#endif /* INET6 */
static void bridge_linkstate(struct ifnet *ifp);
static void bridge_linkcheck(struct bridge_softc *sc);
+/* Netlink */
+static void bridge_nl_register(void);
+static void bridge_nl_unregister(void);
/*
* Use the "null" value from IEEE 802.1Q-2014 Table 9-2
@@ -724,6 +740,7 @@
bridge_detach_cookie = EVENTHANDLER_REGISTER(
ifnet_departure_event, bridge_ifdetach, NULL,
EVENTHANDLER_PRI_ANY);
+ bridge_nl_register();
break;
case MOD_UNLOAD:
EVENTHANDLER_DEREGISTER(ifnet_departure_event,
@@ -732,6 +749,7 @@
bridge_same_p = NULL;
bridge_get_softc_p = NULL;
bridge_member_ifaddrs_p = NULL;
+ bridge_nl_unregister();
break;
default:
return (EOPNOTSUPP);
@@ -1343,33 +1361,36 @@
NET_EPOCH_CALL(bridge_delete_member_cb, &bif->bif_epoch_ctx);
}
-static int
-bridge_ioctl_add(struct bridge_softc *sc, void *arg)
+static void
+bridge_cmd_add(struct bridge_softc *sc, struct ifnet *ifs, int *error,
+ char const **errmsg)
{
- struct ifbreq *req = arg;
- struct bridge_iflist *bif = NULL;
- struct ifnet *ifs;
- int error = 0;
+ struct bridge_iflist *bif;
+
+#define ERRMSG(e, s) \
+ do { \
+ *error = e; \
+ *errmsg = s; \
+ return; \
+ } while (0)
+
+ *error = 0;
- ifs = ifunit(req->ifbr_ifsname);
- if (ifs == NULL)
- return (EXTERROR(ENOENT, "No such interface"));
if (ifs->if_ioctl == NULL) /* must be supported */
- return (EXTERROR(EINVAL, "Interface must support ioctl(2)"));
+ ERRMSG(EINVAL, "Interface must support ioctl(2)");
/* If it's in the span list, it can't be a member. */
CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
if (ifs == bif->bif_ifp)
- return (EXTERROR(EBUSY,
- "Span interface cannot be a member"));
+ ERRMSG(EBUSY, "Span interface cannot be a member");
if (ifs->if_bridge) {
struct bridge_iflist *sbif = ifs->if_bridge;
if (sbif->bif_sc == sc)
- return (EXTERROR(EEXIST,
- "Interface is already a member of this bridge"));
+ ERRMSG(EEXIST,
+ "Interface is already a member of this bridge");
- return EXTERROR(EBUSY,
+ ERRMSG(EBUSY,
"Interface is already a member of another bridge");
}
@@ -1380,7 +1401,7 @@
/* permitted interface types */
break;
default:
- return (EXTERROR(EINVAL, "Unsupported interface type"));
+ ERRMSG(EINVAL, "Unsupported interface type");
}
#ifdef INET6
@@ -1432,15 +1453,15 @@
CK_STAILQ_FOREACH(ifa, &ifs->if_addrhead, ifa_link) {
#ifdef INET
if (ifa->ifa_addr->sa_family == AF_INET)
- return (EXTERROR(EINVAL,
+ ERRMSG(EINVAL,
"Member interface may not have "
- "an IPv4 address configured"));
+ "an IPv4 address configured");
#endif
#ifdef INET6
if (ifa->ifa_addr->sa_family == AF_INET6)
- return (EXTERROR(EINVAL,
+ ERRMSG(EINVAL,
"Member interface may not have "
- "an IPv6 address configured"));
+ "an IPv6 address configured");
#endif
}
}
@@ -1455,21 +1476,19 @@
ifs->if_xname);
ifr.ifr_mtu = sc->sc_ifp->if_mtu;
- error = (*ifs->if_ioctl)(ifs,
- SIOCSIFMTU, (caddr_t)&ifr);
- if (error != 0) {
+ *error = (*ifs->if_ioctl)(ifs, SIOCSIFMTU, (caddr_t)&ifr);
+ if (*error != 0) {
log(LOG_NOTICE, "%s: invalid MTU: %u for"
" new member %s\n", sc->sc_ifp->if_xname,
ifr.ifr_mtu,
ifs->if_xname);
- return (EXTERROR(EINVAL,
- "Failed to set MTU on new member"));
+ ERRMSG(EINVAL, "Failed to set MTU on new member");
}
}
bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
if (bif == NULL)
- return (ENOMEM);
+ ERRMSG(ENOMEM, "Failed to allocate bridge member");
bif->bif_sc = sc;
bif->bif_ifp = ifs;
@@ -1513,13 +1532,34 @@
switch (ifs->if_type) {
case IFT_ETHER:
case IFT_L2VLAN:
- error = ifpromisc(ifs, 1);
+ *error = ifpromisc(ifs, 1);
break;
}
- if (error)
+ if (*error)
bridge_delete_member(sc, bif, 0);
- return (error);
+
+ return;
+#undef ERRMSG
+}
+
+static int
+bridge_ioctl_add(struct bridge_softc *sc, void *arg)
+{
+ struct ifbreq *req = arg;
+ struct ifnet *ifs;
+ const char *errmsg;
+ int error = 0;
+
+ ifs = ifunit(req->ifbr_ifsname);
+ if (ifs == NULL)
+ return (EXTERROR(ENOENT, "No such interface"));
+
+ bridge_cmd_add(sc, ifs, &error, &errmsg);
+ if (error != 0)
+ return (EXTERROR(error, errmsg));
+
+ return (0);
}
static int
@@ -4430,3 +4470,190 @@
}
if_link_state_change(sc->sc_ifp, new_link);
}
+
+/*
+ * Netlink support.
+ */
+
+#define ERROUT(e) do { error = e; goto out; } while (0)
+#define ERRMSG(e, ...) \
+ do { \
+ nlmsg_report_err_msg(npt, __VA_ARGS__); \
+ ERROUT(e); \
+ } while (0)
+
+/* modifymember is used for both add and modify requests */
+
+struct brnl_modifymember {
+ const char *bridge;
+ const char *member;
+};
+
+#define _OUT(_field) offsetof(struct brnl_modifymember, _field)
+static const struct nlattr_parser nla_p_modifymember[] = {
+ { .type = BRIDGE_NL_BRIDGE, .off = _OUT(bridge), .cb = nlattr_get_string },
+ { .type = BRIDGE_NL_MEMBER, .off = _OUT(member), .cb = nlattr_get_string },
+};
+#undef _OUT
+NL_DECLARE_PARSER(modifymember_parser, struct genlmsghdr, nlf_p_empty,
+ nla_p_modifymember);
+
+struct brnl_removemember {
+ const char *bridge;
+ const char *member;
+};
+
+#define _OUT(_field) offsetof(struct brnl_removemember, _field)
+static const struct nlattr_parser nla_p_removemember[] = {
+ { .type = BRIDGE_NL_BRIDGE, .off = _OUT(bridge), .cb = nlattr_get_string },
+ { .type = BRIDGE_NL_MEMBER, .off = _OUT(member), .cb = nlattr_get_string },
+};
+#undef _OUT
+NL_DECLARE_PARSER(removemember_parser, struct genlmsghdr, nlf_p_empty,
+ nla_p_removemember);
+
+static const struct nlhdr_parser *bridge_parsers[] = {
+ &modifymember_parser,
+ &removemember_parser,
+};
+
+static int
+bridge_nl_addmember(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct brnl_modifymember attrs = {};
+ struct bridge_softc *sc;
+ struct ifnet *bridge, *member;
+ const char *errmsg;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &modifymember_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ /* Get the bridge ifnet */
+
+ sc = NULL;
+ member = NULL;
+
+ bridge = ifunit_ref(attrs.bridge);
+ if (bridge == NULL)
+ ERRMSG(ENOENT, "Interface %s does not exist", attrs.bridge);
+
+ if (bridge->if_type != IFT_BRIDGE)
+ ERRMSG(EINVAL, "Interface %s is not a bridge",
+ bridge->if_xname);
+
+ sc = bridge->if_softc;
+ BRIDGE_LOCK(sc);
+
+ /* Get the new member ifnet */
+ member = ifunit_ref(attrs.member);
+ if (member == NULL)
+ ERRMSG(ENOENT, "Interface %s does not exist", attrs.member);
+
+ bridge_cmd_add(sc, member, &error, &errmsg);
+ if (error != 0)
+ ERRMSG(error, "%s", errmsg);
+
+out:
+ if (sc != NULL)
+ BRIDGE_UNLOCK(sc);
+ if (bridge != NULL)
+ if_rele(bridge);
+ if (member != NULL)
+ if_rele(member);
+
+ return (error);
+}
+
+static int
+bridge_nl_removemember(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct brnl_removemember attrs = {};
+ struct bridge_softc *sc;
+ struct ifnet *bridge, *member;
+ struct bridge_iflist *bif;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &removemember_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ /* Get the bridge ifnet */
+
+ sc = NULL;
+ member = NULL;
+
+ bridge = ifunit_ref(attrs.bridge);
+
+ if (bridge == NULL)
+ ERRMSG(ENOENT, "Interface %s does not exist", attrs.bridge);
+
+ if (bridge->if_type != IFT_BRIDGE)
+ ERRMSG(EINVAL, "Interface %s is not a bridge",
+ bridge->if_xname);
+
+ sc = bridge->if_softc;
+ BRIDGE_LOCK(sc);
+
+ /* Get the member bridge_iflist */
+ member = ifunit_ref(attrs.member);
+ if (member == NULL)
+ ERRMSG(ENOENT, "Interface %s does not exist", attrs.member);
+
+ bif = member->if_bridge;
+ if (bif == NULL)
+ ERRMSG(ENOENT, "Interface %s is not in a bridge",
+ member->if_xname);
+
+ if (bif->bif_sc != sc)
+ ERRMSG(ENOENT, "Interface %s is not in bridge %s",
+ member->if_xname, bridge->if_xname);
+
+ /* Delete the member */
+ bridge_delete_member(sc, bif, 0);
+
+out:
+ if (sc != NULL)
+ BRIDGE_UNLOCK(sc);
+ if (bridge != NULL)
+ if_rele(bridge);
+ if (member != NULL)
+ if_rele(member);
+ return error;
+}
+
+static const struct genl_cmd bridge_cmds[] = {
+ {
+ .cmd_num = BRIDGE_NL_CMD_ADDMEMBER,
+ .cmd_name = "ADDMEMBER",
+ .cmd_cb = bridge_nl_addmember,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NET_BRIDGE,
+ },
+ {
+ .cmd_num = BRIDGE_NL_CMD_REMOVEMEMBER,
+ .cmd_name = "REMOVEMEMBER",
+ .cmd_cb = bridge_nl_removemember,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NET_BRIDGE,
+ },
+};
+
+static uint16_t bridge_family_id;
+
+void
+bridge_nl_register(void)
+{
+ NL_VERIFY_PARSERS(bridge_parsers);
+
+ bridge_family_id = genl_register_family(BRIDGE_NL_FAMILY_NAME, 0, 2,
+ BRIDGE_NL_CMD_MAX);
+ genl_register_cmds(bridge_family_id, bridge_cmds, nitems(bridge_cmds));
+}
+
+void
+bridge_nl_unregister(void)
+{
+ genl_unregister_family(bridge_family_id);
+}
diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h
--- a/sys/net/if_bridgevar.h
+++ b/sys/net/if_bridgevar.h
@@ -87,12 +87,48 @@
#include <net/ethernet.h>
#include <net/if.h>
+/*
+ * Netlink interface.
+ */
+
+#define BRIDGE_NL_FAMILY_NAME "if_bridge"
+
+/*
+ * Attributes types
+ */
+#define BRIDGE_NL_BRIDGE 1 /* (string) bridge interface */
+#define BRIDGE_NL_MEMBER 2 /* (string) member interface */
+
+/*
+ * Commands.
+ */
+enum {
+ BRIDGE_NL_CMD_UNSPEC = 0,
+
+ /*
+ * BRIDGE_NL_CMD_ADDMEMBER: Add a new interface to the bridge.
+ * Arguments: BRIDGE_NL_BRIDGE: the bridge to add the member to
+ * BRIDGE_NL_MEMBER: the interface to add
+ */
+ BRIDGE_NL_CMD_ADDMEMBER,
+
+ /*
+ * BRIDGE_NL_CMD_REMOVEMEMBER: Remove an interface from a bridge.
+ * Arguments: BRIDGE_NL_BRIDGE: the bridge to remove the member from
+ * BRIDGE_NL_MEMBER: the interface to remove
+ */
+ BRIDGE_NL_CMD_REMOVEMEMBER,
+
+ __BRIDGE_NL_CMD_LAST
+};
+#define BRIDGE_NL_CMD_MAX (__BRIDGE_NL_CMD_LAST - 1)
+
/*
* Commands used in the SIOCSDRVSPEC ioctl. Note the lookup of the
* bridge interface itself is keyed off the ifdrv structure.
*/
-#define BRDGADD 0 /* add bridge member (ifbreq) */
-#define BRDGDEL 1 /* delete bridge member (ifbreq) */
+#define BRDGADD 0 /* compat; use Netlink instead */
+#define BRDGDEL 1 /* compat; use Netlink instead */
#define BRDGGIFFLGS 2 /* get member if flags (ifbreq) */
#define BRDGSIFFLGS 3 /* set member if flags (ifbreq) */
#define BRDGSCACHE 4 /* set cache size (ifbrparam) */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Oct 22, 7:52 PM (5 m, 8 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24064841
Default Alt Text
D51238.id158304.diff (13 KB)
Attached To
Mode
D51238: bridge: add a netlink interface
Attached
Detach File
Event Timeline
Log In to Comment