Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_lagg.c
Show All 17 Lines | |||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#include "opt_ratelimit.h" | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
static void lagg_port_ifdetach(void *arg __unused, struct ifnet *); | static void lagg_port_ifdetach(void *arg __unused, struct ifnet *); | ||||
#ifdef LAGG_PORT_STACKING | #ifdef LAGG_PORT_STACKING | ||||
static int lagg_port_checkstacking(struct lagg_softc *); | static int lagg_port_checkstacking(struct lagg_softc *); | ||||
#endif | #endif | ||||
static void lagg_port2req(struct lagg_port *, struct lagg_reqport *); | static void lagg_port2req(struct lagg_port *, struct lagg_reqport *); | ||||
static void lagg_init(void *); | static void lagg_init(void *); | ||||
static void lagg_stop(struct lagg_softc *); | static void lagg_stop(struct lagg_softc *); | ||||
static int lagg_ioctl(struct ifnet *, u_long, caddr_t); | static int lagg_ioctl(struct ifnet *, u_long, caddr_t); | ||||
#ifdef RATELIMIT | |||||
static int lagg_snd_tag_alloc(struct ifnet *, | |||||
union if_snd_tag_alloc_params *, | |||||
struct m_snd_tag **); | |||||
#endif | |||||
static int lagg_ether_setmulti(struct lagg_softc *); | static int lagg_ether_setmulti(struct lagg_softc *); | ||||
static int lagg_ether_cmdmulti(struct lagg_port *, int); | static int lagg_ether_cmdmulti(struct lagg_port *, int); | ||||
static int lagg_setflag(struct lagg_port *, int, int, | static int lagg_setflag(struct lagg_port *, int, int, | ||||
int (*func)(struct ifnet *, int)); | int (*func)(struct ifnet *, int)); | ||||
static int lagg_setflags(struct lagg_port *, int status); | static int lagg_setflags(struct lagg_port *, int status); | ||||
static uint64_t lagg_get_counter(struct ifnet *ifp, ift_counter cnt); | static uint64_t lagg_get_counter(struct ifnet *ifp, ift_counter cnt); | ||||
static int lagg_transmit(struct ifnet *, struct mbuf *); | static int lagg_transmit(struct ifnet *, struct mbuf *); | ||||
static void lagg_qflush(struct ifnet *); | static void lagg_qflush(struct ifnet *); | ||||
▲ Show 20 Lines • Show All 369 Lines • ▼ Show 20 Lines | lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params) | ||||
if_initname(ifp, laggname, unit); | if_initname(ifp, laggname, unit); | ||||
ifp->if_softc = sc; | ifp->if_softc = sc; | ||||
ifp->if_transmit = lagg_transmit; | ifp->if_transmit = lagg_transmit; | ||||
ifp->if_qflush = lagg_qflush; | ifp->if_qflush = lagg_qflush; | ||||
ifp->if_init = lagg_init; | ifp->if_init = lagg_init; | ||||
ifp->if_ioctl = lagg_ioctl; | ifp->if_ioctl = lagg_ioctl; | ||||
ifp->if_get_counter = lagg_get_counter; | ifp->if_get_counter = lagg_get_counter; | ||||
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | ||||
#ifdef RATELIMIT | |||||
ifp->if_snd_tag_alloc = lagg_snd_tag_alloc; | |||||
ifp->if_capenable = ifp->if_capabilities = IFCAP_HWSTATS | IFCAP_TXRTLMT; | |||||
#else | |||||
ifp->if_capenable = ifp->if_capabilities = IFCAP_HWSTATS; | ifp->if_capenable = ifp->if_capabilities = IFCAP_HWSTATS; | ||||
#endif | |||||
/* | /* | ||||
* Attach as an ordinary ethernet device, children will be attached | * Attach as an ordinary ethernet device, children will be attached | ||||
* as special device IFT_IEEE8023ADLAG. | * as special device IFT_IEEE8023ADLAG. | ||||
*/ | */ | ||||
ether_ifattach(ifp, eaddr); | ether_ifattach(ifp, eaddr); | ||||
sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | ||||
▲ Show 20 Lines • Show All 1,028 Lines • ▼ Show 20 Lines | case SIOCSIFMTU: | ||||
break; | break; | ||||
default: | default: | ||||
error = ether_ioctl(ifp, cmd, data); | error = ether_ioctl(ifp, cmd, data); | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
#ifdef RATELIMIT | |||||
static int | |||||
lagg_snd_tag_alloc(struct ifnet *ifp, | |||||
union if_snd_tag_alloc_params *params, | |||||
struct m_snd_tag **ppmt) | |||||
{ | |||||
struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc; | |||||
struct lagg_port *lp; | |||||
struct lagg_lb *lb; | |||||
uint32_t p; | |||||
switch (sc->sc_proto) { | |||||
case LAGG_PROTO_FAILOVER: | |||||
lp = lagg_link_active(sc, sc->sc_primary); | |||||
break; | |||||
case LAGG_PROTO_LOADBALANCE: | |||||
if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) == 0 || | |||||
params->hdr.flowtype == M_HASHTYPE_NONE) | |||||
return (EOPNOTSUPP); | |||||
p = params->hdr.flowid >> sc->flowid_shift; | |||||
p %= sc->sc_count; | |||||
lb = (struct lagg_lb *)sc->sc_psc; | |||||
lp = lb->lb_ports[p]; | |||||
lp = lagg_link_active(sc, lp); | |||||
break; | |||||
case LAGG_PROTO_LACP: | |||||
if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) == 0 || | |||||
params->hdr.flowtype == M_HASHTYPE_NONE) | |||||
return (EOPNOTSUPP); | |||||
lp = lacp_select_tx_port_by_hash(sc, params->hdr.flowid); | |||||
break; | |||||
default: | |||||
return (EOPNOTSUPP); | |||||
} | |||||
if (lp == NULL) | |||||
return (EOPNOTSUPP); | |||||
ifp = lp->lp_ifp; | |||||
if (ifp == NULL || ifp->if_snd_tag_alloc == NULL || | |||||
(ifp->if_capenable & IFCAP_TXRTLMT) == 0) | |||||
return (EOPNOTSUPP); | |||||
/* forward allocation request */ | |||||
return (ifp->if_snd_tag_alloc(ifp, params, ppmt)); | |||||
gallatin: How do you handle already allocated tags when the underlying ifp fails?
Eg, the way that lagg… | |||||
Done Inline ActionsHi Drew, When a mbuf is delivered to its final network interface, the network interface driver needs to check if "ifp" is equal to the ifp pointer inside the m_snd_tag. If the network interface pointers are equal we know the packet is on the right interface and continue, else we return EAGAIN and then the ip_output()/ip6_output() will free the mst and allocate a new one on the new destination ifp. This way we avoid superfluous checks in the fast path for lagg. --HPS hselasky: Hi Drew,
When a mbuf is delivered to its final network interface, the network interface driver… | |||||
Done Inline ActionsAh, that makes sense. Without seeing the driver side matching this version, it is hard to know these things :) gallatin: Ah, that makes sense. Without seeing the driver side matching this version, it is hard to know… | |||||
} | |||||
#endif | |||||
static int | static int | ||||
lagg_ether_setmulti(struct lagg_softc *sc) | lagg_ether_setmulti(struct lagg_softc *sc) | ||||
{ | { | ||||
struct lagg_port *lp; | struct lagg_port *lp; | ||||
LAGG_WLOCK_ASSERT(sc); | LAGG_WLOCK_ASSERT(sc); | ||||
▲ Show 20 Lines • Show All 682 Lines • Show Last 20 Lines |
How do you handle already allocated tags when the underlying ifp fails?
Eg, the way that lagg is supposed to work is that if a link fails, lagg is supposed to stop using the failed link. Maybe I'm missing something, but I don't see a mechanism to shoot down these tags when a link does down, or LACP otherwise fails.