summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2020-10-22 09:47:12 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2020-10-22 09:47:12 +0000
commita92c4bb62ad107d867863f04937f65f23bce0837 (patch)
tree0a6b9d9a76269b2e60f01f2fbf93bdf7eddaa46c
parent18b8496c23fa9e88c3ac6d6e477896683c4f3847 (diff)
Notes
-rw-r--r--sbin/ifconfig/ifconfig.88
-rw-r--r--sbin/ifconfig/iflagg.c31
-rw-r--r--share/man/man4/lagg.411
-rw-r--r--sys/net/ieee8023ad_lacp.c1
-rw-r--r--sys/net/if_ethersubr.c6
-rw-r--r--sys/net/if_infiniband.c14
-rw-r--r--sys/net/if_lagg.c273
-rw-r--r--sys/net/if_lagg.h37
-rw-r--r--sys/net/if_types.h1
9 files changed, 335 insertions, 47 deletions
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 2978fbdb5691..da7e3f049a59 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
-.Dd September 17, 2020
+.Dd October 21, 2020
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -2481,6 +2481,12 @@ Set to 0 to disable.
.Pp
The following parameters are specific to lagg interfaces:
.Bl -tag -width indent
+.It Cm laggtype Ar type
+When creating a lagg interface the type can be specified as either
+.Cm ethernet
+or
+.Cm infiniband .
+If not specified ethernet is the default lagg type.
.It Cm laggport Ar interface
Add the interface named by
.Ar interface
diff --git a/sbin/ifconfig/iflagg.c b/sbin/ifconfig/iflagg.c
index a892ffd21eb0..63a5928a5d44 100644
--- a/sbin/ifconfig/iflagg.c
+++ b/sbin/ifconfig/iflagg.c
@@ -30,7 +30,11 @@ static const char rcsid[] =
#include "ifconfig.h"
-char lacpbuf[120]; /* LACP peer '[(a,a,a),(p,p,p)]' */
+static struct iflaggparam params = {
+ .lagg_type = LAGG_TYPE_DEFAULT,
+};
+
+static char lacpbuf[120]; /* LACP peer '[(a,a,a),(p,p,p)]' */
static void
setlaggport(const char *val, int d, int s, const struct afswtch *afp)
@@ -301,7 +305,31 @@ lagg_status(int s)
}
}
+static
+DECL_CMD_FUNC(setlaggtype, arg, d)
+{
+ static const struct lagg_types lt[] = LAGG_TYPES;
+ int i;
+
+ for (i = 0; i < nitems(lt); i++) {
+ if (strcmp(arg, lt[i].lt_name) == 0) {
+ params.lagg_type = lt[i].lt_value;
+ return;
+ }
+ }
+ errx(1, "invalid lagg type: %s", arg);
+}
+
+static void
+lagg_create(int s, struct ifreq *ifr)
+{
+ ifr->ifr_data = (caddr_t) &params;
+ if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+ err(1, "SIOCIFCREATE2");
+}
+
static struct cmd lagg_cmds[] = {
+ DEF_CLONE_CMD_ARG("laggtype", setlaggtype),
DEF_CMD_ARG("laggport", setlaggport),
DEF_CMD_ARG("-laggport", unsetlaggport),
DEF_CMD_ARG("laggproto", setlaggproto),
@@ -335,4 +363,5 @@ lagg_ctor(void)
for (i = 0; i < nitems(lagg_cmds); i++)
cmd_register(&lagg_cmds[i]);
af_register(&af_lagg);
+ clone_setdefcallback("lagg", lagg_create);
}
diff --git a/share/man/man4/lagg.4 b/share/man/man4/lagg.4
index 934593551905..f7d8e1c5e1f5 100644
--- a/share/man/man4/lagg.4
+++ b/share/man/man4/lagg.4
@@ -16,7 +16,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 18, 2017
+.Dd October 21, 2020
.Dt LAGG 4
.Os
.Sh NAME
@@ -192,6 +192,15 @@ device will be used:
.Pp
(Note the mac address of the wireless device is forced to match the wired
device as a workaround.)
+.Pp
+The following example shows how to create an infiniband failover interface.
+.Bd -literal -offset indent
+# ifconfig ib0 up
+# ifconfig ib1 up
+# ifconfig lagg0 create laggtype infiniband
+# ifconfig lagg0 laggproto failover laggport ib0 laggport ib1 \e
+ 1.1.1.1 netmask 255.255.255.0
+.Ed
.Sh SEE ALSO
.Xr ng_one2many 4 ,
.Xr ifconfig 8 ,
diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c
index 969efcd58a36..6deecb9fff6b 100644
--- a/sys/net/ieee8023ad_lacp.c
+++ b/sys/net/ieee8023ad_lacp.c
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/ethernet.h>
+#include <net/infiniband.h>
#include <net/if_media.h>
#include <net/if_types.h>
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index ccf2c4383284..8731cb5b0188 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -110,7 +110,7 @@ void (*vlan_input_p)(struct ifnet *, struct mbuf *);
void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
/* if_lagg(4) support */
-struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
+struct mbuf *(*lagg_input_ethernet_p)(struct ifnet *, struct mbuf *);
static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -608,9 +608,9 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
/* Handle input from a lagg(4) port */
if (ifp->if_type == IFT_IEEE8023ADLAG) {
- KASSERT(lagg_input_p != NULL,
+ KASSERT(lagg_input_ethernet_p != NULL,
("%s: if_lagg not loaded!", __func__));
- m = (*lagg_input_p)(ifp, m);
+ m = (*lagg_input_ethernet_p)(ifp, m);
if (m != NULL)
ifp = m->m_pkthdr.rcvif;
else {
diff --git a/sys/net/if_infiniband.c b/sys/net/if_infiniband.c
index 7800aa54ab35..ca86724b0561 100644
--- a/sys/net/if_infiniband.c
+++ b/sys/net/if_infiniband.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/if_media.h>
+#include <net/if_lagg.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
@@ -58,6 +59,9 @@ __FBSDID("$FreeBSD$");
#include <security/mac/mac_framework.h>
+/* if_lagg(4) support */
+struct mbuf *(*lagg_input_infiniband_p)(struct ifnet *, struct mbuf *);
+
#ifdef INET
static inline void
infiniband_ipv4_multicast_map(uint32_t addr,
@@ -346,6 +350,16 @@ infiniband_input(struct ifnet *ifp, struct mbuf *m)
/* Direct packet to correct FIB based on interface config. */
M_SETFIB(m, ifp->if_fib);
+ /* Handle input from a lagg<N> port */
+ if (ifp->if_type == IFT_INFINIBANDLAG) {
+ KASSERT(lagg_input_infiniband_p != NULL,
+ ("%s: if_lagg not loaded!", __func__));
+ m = (*lagg_input_infiniband_p)(ifp, m);
+ if (__predict_false(m == NULL))
+ goto done;
+ ifp = m->m_pkthdr.rcvif;
+ }
+
/*
* Dispatch frame to upper layer.
*/
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index ba9c2d2f58fe..dee4a5be6cca 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <net/bpf.h>
#include <net/route.h>
#include <net/vnet.h>
+#include <net/infiniband.h>
#if defined(INET) || defined(INET6)
#include <netinet/in.h>
@@ -131,7 +132,8 @@ static MALLOC_DEFINE(M_LAGG, laggname, "802.3AD Link Aggregation Interface");
static void lagg_capabilities(struct lagg_softc *);
static int lagg_port_create(struct lagg_softc *, struct ifnet *);
static int lagg_port_destroy(struct lagg_port *, int);
-static struct mbuf *lagg_input(struct ifnet *, struct mbuf *);
+static struct mbuf *lagg_input_ethernet(struct ifnet *, struct mbuf *);
+static struct mbuf *lagg_input_infiniband(struct ifnet *, struct mbuf *);
static void lagg_linkstate(struct lagg_softc *);
static void lagg_port_state(struct ifnet *, int);
static int lagg_port_ioctl(struct ifnet *, u_long, caddr_t);
@@ -164,7 +166,8 @@ static int lagg_setflag(struct lagg_port *, int, int,
int (*func)(struct ifnet *, int));
static int lagg_setflags(struct lagg_port *, int status);
static uint64_t lagg_get_counter(struct ifnet *ifp, ift_counter cnt);
-static int lagg_transmit(struct ifnet *, struct mbuf *);
+static int lagg_transmit_ethernet(struct ifnet *, struct mbuf *);
+static int lagg_transmit_infiniband(struct ifnet *, struct mbuf *);
static void lagg_qflush(struct ifnet *);
static int lagg_media_change(struct ifnet *);
static void lagg_media_status(struct ifnet *, struct ifmediareq *);
@@ -327,7 +330,8 @@ lagg_modevent(module_t mod, int type, void *data)
switch (type) {
case MOD_LOAD:
- lagg_input_p = lagg_input;
+ lagg_input_ethernet_p = lagg_input_ethernet;
+ lagg_input_infiniband_p = lagg_input_infiniband;
lagg_linkstate_p = lagg_port_state;
lagg_detach_cookie = EVENTHANDLER_REGISTER(
ifnet_departure_event, lagg_port_ifdetach, NULL,
@@ -336,7 +340,8 @@ lagg_modevent(module_t mod, int type, void *data)
case MOD_UNLOAD:
EVENTHANDLER_DEREGISTER(ifnet_departure_event,
lagg_detach_cookie);
- lagg_input_p = NULL;
+ lagg_input_ethernet_p = NULL;
+ lagg_input_infiniband_p = NULL;
lagg_linkstate_p = NULL;
break;
default:
@@ -353,6 +358,7 @@ static moduledata_t lagg_mod = {
DECLARE_MODULE(if_lagg, lagg_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_VERSION(if_lagg, 1);
+MODULE_DEPEND(if_lagg, if_infiniband, 1, 1, 1);
static void
lagg_proto_attach(struct lagg_softc *sc, lagg_proto pr)
@@ -504,18 +510,48 @@ lagg_unregister_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag)
static int
lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
{
+ struct iflaggparam iflp;
struct lagg_softc *sc;
struct ifnet *ifp;
- static const u_char eaddr[6]; /* 00:00:00:00:00:00 */
+ int if_type;
+ int error;
+ static const uint8_t eaddr[LAGG_ADDR_LEN];
+ static const uint8_t ib_bcast_addr[INFINIBAND_ADDR_LEN] = {
+ 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (params != NULL) {
+ error = copyin(params, &iflp, sizeof(iflp));
+ if (error)
+ return (error);
+
+ switch (iflp.lagg_type) {
+ case LAGG_TYPE_ETHERNET:
+ if_type = IFT_ETHER;
+ break;
+ case LAGG_TYPE_INFINIBAND:
+ if_type = IFT_INFINIBAND;
+ break;
+ default:
+ return (EINVAL);
+ }
+ } else {
+ if_type = IFT_ETHER;
+ }
sc = malloc(sizeof(*sc), M_LAGG, M_WAITOK|M_ZERO);
- ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
+ ifp = sc->sc_ifp = if_alloc(if_type);
if (ifp == NULL) {
free(sc, M_LAGG);
return (ENOSPC);
}
LAGG_SX_INIT(sc);
+ mtx_init(&sc->sc_mtx, "lagg-mtx", NULL, MTX_DEF);
+ callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
+
LAGG_XLOCK(sc);
if (V_def_use_flowid)
sc->sc_opts |= LAGG_OPT_USE_FLOWID;
@@ -530,15 +566,25 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
CK_SLIST_INIT(&sc->sc_ports);
- /* Initialise pseudo media types */
- ifmedia_init(&sc->sc_media, 0, lagg_media_change,
- lagg_media_status);
- ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
- ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
+ switch (if_type) {
+ case IFT_ETHER:
+ /* Initialise pseudo media types */
+ ifmedia_init(&sc->sc_media, 0, lagg_media_change,
+ lagg_media_status);
+ ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
- if_initname(ifp, laggname, unit);
+ if_initname(ifp, laggname, unit);
+ ifp->if_transmit = lagg_transmit_ethernet;
+ break;
+ case IFT_INFINIBAND:
+ if_initname(ifp, laggname, unit);
+ ifp->if_transmit = lagg_transmit_infiniband;
+ break;
+ default:
+ break;
+ }
ifp->if_softc = sc;
- ifp->if_transmit = lagg_transmit;
ifp->if_qflush = lagg_qflush;
ifp->if_init = lagg_init;
ifp->if_ioctl = lagg_ioctl;
@@ -555,9 +601,18 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
/*
* Attach as an ordinary ethernet device, children will be attached
- * as special device IFT_IEEE8023ADLAG.
+ * as special device IFT_IEEE8023ADLAG or IFT_INFINIBANDLAG.
*/
- ether_ifattach(ifp, eaddr);
+ switch (if_type) {
+ case IFT_ETHER:
+ ether_ifattach(ifp, eaddr);
+ break;
+ case IFT_INFINIBAND:
+ infiniband_ifattach(ifp, eaddr, ib_bcast_addr);
+ break;
+ default:
+ break;
+ }
sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
lagg_register_vlan, sc, EVENTHANDLER_PRI_FIRST);
@@ -595,14 +650,24 @@ lagg_clone_destroy(struct ifnet *ifp)
lagg_proto_detach(sc);
LAGG_XUNLOCK(sc);
- ifmedia_removeall(&sc->sc_media);
- ether_ifdetach(ifp);
+ switch (ifp->if_type) {
+ case IFT_ETHER:
+ ifmedia_removeall(&sc->sc_media);
+ ether_ifdetach(ifp);
+ break;
+ case IFT_INFINIBAND:
+ infiniband_ifdetach(ifp);
+ break;
+ default:
+ break;
+ }
if_free(ifp);
LAGG_LIST_LOCK();
SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries);
LAGG_LIST_UNLOCK();
+ mtx_destroy(&sc->sc_mtx);
LAGG_SX_DESTROY(sc);
free(sc, M_LAGG);
}
@@ -669,6 +734,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
struct lagg_port *lp, *tlp;
struct ifreq ifr;
int error, i, oldmtu;
+ int if_type;
uint64_t *pval;
LAGG_XLOCK_ASSERT(sc);
@@ -695,9 +761,22 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
return (EBUSY);
}
- /* XXX Disallow non-ethernet interfaces (this should be any of 802) */
- if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN)
- return (EPROTONOSUPPORT);
+ switch (sc->sc_ifp->if_type) {
+ case IFT_ETHER:
+ /* XXX Disallow non-ethernet interfaces (this should be any of 802) */
+ if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN)
+ return (EPROTONOSUPPORT);
+ if_type = IFT_IEEE8023ADLAG;
+ break;
+ case IFT_INFINIBAND:
+ /* XXX Disallow non-infiniband interfaces */
+ if (ifp->if_type != IFT_INFINIBAND)
+ return (EPROTONOSUPPORT);
+ if_type = IFT_INFINIBANDLAG;
+ break;
+ default:
+ break;
+ }
/* Allow the first Ethernet member to define the MTU */
oldmtu = -1;
@@ -754,14 +833,14 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
if_ref(ifp);
lp->lp_ifp = ifp;
- bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN);
+ bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ifp->if_addrlen);
lp->lp_ifcapenable = ifp->if_capenable;
if (CK_SLIST_EMPTY(&sc->sc_ports)) {
- bcopy(IF_LLADDR(ifp), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
+ bcopy(IF_LLADDR(ifp), IF_LLADDR(sc->sc_ifp), ifp->if_addrlen);
lagg_proto_lladdr(sc);
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
} else {
- if_setlladdr(ifp, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
+ if_setlladdr(ifp, IF_LLADDR(sc->sc_ifp), ifp->if_addrlen);
}
lagg_setflags(lp, 1);
@@ -770,7 +849,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
/* Change the interface type */
lp->lp_iftype = ifp->if_type;
- ifp->if_type = IFT_IEEE8023ADLAG;
+ ifp->if_type = if_type;
ifp->if_lagg = lp;
lp->lp_ioctl = ifp->if_ioctl;
ifp->if_ioctl = lagg_port_ioctl;
@@ -887,15 +966,15 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport)
/* Update the primary interface */
if (lp == sc->sc_primary) {
- uint8_t lladdr[ETHER_ADDR_LEN];
+ uint8_t lladdr[LAGG_ADDR_LEN];
if ((lp0 = CK_SLIST_FIRST(&sc->sc_ports)) == NULL)
- bzero(&lladdr, ETHER_ADDR_LEN);
+ bzero(&lladdr, LAGG_ADDR_LEN);
else
- bcopy(lp0->lp_lladdr, lladdr, ETHER_ADDR_LEN);
+ bcopy(lp0->lp_lladdr, lladdr, LAGG_ADDR_LEN);
sc->sc_primary = lp0;
if (sc->sc_destroying == 0) {
- bcopy(lladdr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
+ bcopy(lladdr, IF_LLADDR(sc->sc_ifp), sc->sc_ifp->if_addrlen);
lagg_proto_lladdr(sc);
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
}
@@ -905,7 +984,7 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport)
* as well, to switch from old lladdr to its 'real' one)
*/
CK_SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries)
- if_setlladdr(lp_ptr->lp_ifp, lladdr, ETHER_ADDR_LEN);
+ if_setlladdr(lp_ptr->lp_ifp, lladdr, lp_ptr->lp_ifp->if_addrlen);
}
if (lp->lp_ifflags)
@@ -914,7 +993,7 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport)
if (lp->lp_detaching == 0) {
lagg_setflags(lp, 0);
lagg_setcaps(lp, lp->lp_ifcapenable);
- if_setlladdr(ifp, lp->lp_lladdr, ETHER_ADDR_LEN);
+ if_setlladdr(ifp, lp->lp_lladdr, ifp->if_addrlen);
}
/*
@@ -938,9 +1017,15 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
int error = 0;
/* Should be checked by the caller */
- if (ifp->if_type != IFT_IEEE8023ADLAG ||
- (lp = ifp->if_lagg) == NULL || (sc = lp->lp_softc) == NULL)
+ switch (ifp->if_type) {
+ case IFT_IEEE8023ADLAG:
+ case IFT_INFINIBANDLAG:
+ if ((lp = ifp->if_lagg) == NULL || (sc = lp->lp_softc) == NULL)
+ goto fallback;
+ break;
+ default:
goto fallback;
+ }
switch (cmd) {
case SIOCGLAGGPORT:
@@ -1130,6 +1215,44 @@ lagg_port2req(struct lagg_port *lp, struct lagg_reqport *rp)
}
static void
+lagg_watchdog_infiniband(void *arg)
+{
+ struct lagg_softc *sc;
+ struct lagg_port *lp;
+ struct ifnet *ifp;
+ struct ifnet *lp_ifp;
+
+ sc = arg;
+
+ /*
+ * Because infiniband nodes have a fixed MAC address, which is
+ * generated by the so-called GID, we need to regularly update
+ * the link level address of the parent lagg<N> device when
+ * the active port changes. Possibly we could piggy-back on
+ * link up/down events aswell, but using a timer also provides
+ * a guarantee against too frequent events. This operation
+ * does not have to be atomic.
+ */
+ LAGG_RLOCK();
+ lp = lagg_link_active(sc, sc->sc_primary);
+ if (lp != NULL) {
+ ifp = sc->sc_ifp;
+ lp_ifp = lp->lp_ifp;
+
+ if (ifp != NULL && lp_ifp != NULL &&
+ memcmp(IF_LLADDR(ifp), IF_LLADDR(lp_ifp), ifp->if_addrlen) != 0) {
+ memcpy(IF_LLADDR(ifp), IF_LLADDR(lp_ifp), ifp->if_addrlen);
+ CURVNET_SET(ifp->if_vnet);
+ EVENTHANDLER_INVOKE(iflladdr_event, ifp);
+ CURVNET_RESTORE();
+ }
+ }
+ LAGG_RUNLOCK();
+
+ callout_reset(&sc->sc_watchdog, hz, &lagg_watchdog_infiniband, arg);
+}
+
+static void
lagg_init(void *xsc)
{
struct lagg_softc *sc = (struct lagg_softc *)xsc;
@@ -1151,12 +1274,18 @@ lagg_init(void *xsc)
*/
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
if (memcmp(IF_LLADDR(ifp), IF_LLADDR(lp->lp_ifp),
- ETHER_ADDR_LEN) != 0)
- if_setlladdr(lp->lp_ifp, IF_LLADDR(ifp), ETHER_ADDR_LEN);
+ ifp->if_addrlen) != 0)
+ if_setlladdr(lp->lp_ifp, IF_LLADDR(ifp), ifp->if_addrlen);
}
lagg_proto_init(sc);
+ if (ifp->if_type == IFT_INFINIBAND) {
+ mtx_lock(&sc->sc_mtx);
+ lagg_watchdog_infiniband(sc);
+ mtx_unlock(&sc->sc_mtx);
+ }
+
LAGG_XUNLOCK(sc);
}
@@ -1173,6 +1302,12 @@ lagg_stop(struct lagg_softc *sc)
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
lagg_proto_stop(sc);
+
+ mtx_lock(&sc->sc_mtx);
+ callout_stop(&sc->sc_watchdog);
+ mtx_unlock(&sc->sc_mtx);
+
+ callout_drain(&sc->sc_watchdog);
}
static int
@@ -1228,7 +1363,12 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = EPROTONOSUPPORT;
break;
}
-
+ /* Infiniband only supports the failover protocol. */
+ if (ra->ra_proto != LAGG_PROTO_FAILOVER &&
+ ifp->if_type == IFT_INFINIBAND) {
+ error = EPROTONOSUPPORT;
+ break;
+ }
LAGG_XLOCK(sc);
lagg_proto_detach(sc);
LAGG_UNLOCK_ASSERT();
@@ -1546,7 +1686,10 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
- error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
+ if (ifp->if_type == IFT_INFINIBAND)
+ error = EINVAL;
+ else
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
break;
case SIOCSIFCAP:
@@ -1855,7 +1998,7 @@ lagg_setflags(struct lagg_port *lp, int status)
}
static int
-lagg_transmit(struct ifnet *ifp, struct mbuf *m)
+lagg_transmit_ethernet(struct ifnet *ifp, struct mbuf *m)
{
struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
int error;
@@ -1880,6 +2023,32 @@ lagg_transmit(struct ifnet *ifp, struct mbuf *m)
return (error);
}
+static int
+lagg_transmit_infiniband(struct ifnet *ifp, struct mbuf *m)
+{
+ struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
+ int error;
+
+#if defined(KERN_TLS) || defined(RATELIMIT)
+ if (m->m_pkthdr.csum_flags & CSUM_SND_TAG)
+ MPASS(m->m_pkthdr.snd_tag->ifp == ifp);
+#endif
+ LAGG_RLOCK();
+ /* We need a Tx algorithm and at least one port */
+ if (sc->sc_proto == LAGG_PROTO_NONE || sc->sc_count == 0) {
+ LAGG_RUNLOCK();
+ m_freem(m);
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ return (ENXIO);
+ }
+
+ INFINIBAND_BPF_MTAP(ifp, m);
+
+ error = lagg_proto_start(sc, m);
+ LAGG_RUNLOCK();
+ return (error);
+}
+
/*
* The ifp->if_qflush entry point for lagg(4) is no-op.
*/
@@ -1889,7 +2058,7 @@ lagg_qflush(struct ifnet *ifp __unused)
}
static struct mbuf *
-lagg_input(struct ifnet *ifp, struct mbuf *m)
+lagg_input_ethernet(struct ifnet *ifp, struct mbuf *m)
{
struct lagg_port *lp = ifp->if_lagg;
struct lagg_softc *sc = lp->lp_softc;
@@ -1916,6 +2085,34 @@ lagg_input(struct ifnet *ifp, struct mbuf *m)
return (m);
}
+static struct mbuf *
+lagg_input_infiniband(struct ifnet *ifp, struct mbuf *m)
+{
+ struct lagg_port *lp = ifp->if_lagg;
+ struct lagg_softc *sc = lp->lp_softc;
+ struct ifnet *scifp = sc->sc_ifp;
+
+ LAGG_RLOCK();
+ if ((scifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
+ lp->lp_detaching != 0 ||
+ sc->sc_proto == LAGG_PROTO_NONE) {
+ LAGG_RUNLOCK();
+ m_freem(m);
+ return (NULL);
+ }
+
+ INFINIBAND_BPF_MTAP(scifp, m);
+
+ m = lagg_proto_input(sc, lp, m);
+ if (m != NULL && (scifp->if_flags & IFF_MONITOR) != 0) {
+ m_freem(m);
+ m = NULL;
+ }
+
+ LAGG_RUNLOCK();
+ return (m);
+}
+
static int
lagg_media_change(struct ifnet *ifp)
{
diff --git a/sys/net/if_lagg.h b/sys/net/if_lagg.h
index 738bfdcecf09..fc3e782d4444 100644
--- a/sys/net/if_lagg.h
+++ b/sys/net/if_lagg.h
@@ -72,6 +72,33 @@ struct lagg_protos {
{ "default", LAGG_PROTO_DEFAULT } \
}
+/* Supported lagg TYPEs */
+typedef enum {
+ LAGG_TYPE_ETHERNET = 0, /* ethernet (default) */
+ LAGG_TYPE_INFINIBAND, /* infiniband */
+ LAGG_TYPE_MAX,
+} lagg_type;
+
+struct lagg_types {
+ const char *lt_name;
+ lagg_type lt_value;
+};
+
+#define LAGG_TYPE_DEFAULT LAGG_TYPE_ETHERNET
+#define LAGG_TYPES { \
+ { "ethernet", LAGG_TYPE_ETHERNET }, \
+ { "infiniband", LAGG_TYPE_INFINIBAND }, \
+}
+
+/*
+ * lagg create clone params
+ */
+struct iflaggparam {
+ uint8_t lagg_type; /* see LAGG_TYPE_XXX */
+ uint8_t reserved_8[3];
+ uint32_t reserved_32[3];
+};
+
/*
* lagg ioctls.
*/
@@ -206,7 +233,7 @@ struct lagg_counters {
struct lagg_softc {
struct ifnet *sc_ifp; /* virtual interface */
- struct rmlock sc_mtx;
+ struct mtx sc_mtx; /* watchdog mutex */
struct sx sc_sx;
int sc_proto; /* lagg protocol */
u_int sc_count; /* number of ports */
@@ -230,12 +257,15 @@ struct lagg_softc {
u_int sc_opts;
int flowid_shift; /* shift the flowid */
struct lagg_counters detached_counters; /* detached ports sum */
+ struct callout sc_watchdog; /* watchdog timer */
};
struct lagg_port {
struct ifnet *lp_ifp; /* physical interface */
struct lagg_softc *lp_softc; /* parent lagg */
- uint8_t lp_lladdr[ETHER_ADDR_LEN];
+#define LAGG_ADDR_LEN \
+ MAX(INFINIBAND_ADDR_LEN, ETHER_ADDR_LEN)
+ uint8_t lp_lladdr[LAGG_ADDR_LEN];
u_char lp_iftype; /* interface type */
uint32_t lp_prio; /* port priority */
@@ -257,7 +287,8 @@ struct lagg_port {
struct epoch_context lp_epoch_ctx;
};
-extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
+extern struct mbuf *(*lagg_input_ethernet_p)(struct ifnet *, struct mbuf *);
+extern struct mbuf *(*lagg_input_infiniband_p)(struct ifnet *, struct mbuf *);
extern void (*lagg_linkstate_p)(struct ifnet *, int );
int lagg_enqueue(struct ifnet *, struct mbuf *);
diff --git a/sys/net/if_types.h b/sys/net/if_types.h
index 61c432ba890f..1103d5f90928 100644
--- a/sys/net/if_types.h
+++ b/sys/net/if_types.h
@@ -242,6 +242,7 @@ typedef enum {
IFT_OPTICALCHANNEL = 0xc3, /* Optical Channel */
IFT_OPTICALTRANSPORT = 0xc4, /* Optical Transport */
IFT_INFINIBAND = 0xc7, /* Infiniband */
+ IFT_INFINIBANDLAG = 0xc8, /* Infiniband Link Aggregate */
IFT_BRIDGE = 0xd1, /* Transparent bridge interface */
IFT_STF = 0xd7, /* 6to4 interface */