Page MenuHomeFreeBSD

D51238.id158304.diff
No OneTemporary

D51238.id158304.diff

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

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)

Event Timeline