Add the trunk(4) driver for providing link aggregation, failover and fault

tolerance.  This driver allows aggregation of multiple network interfaces as
one virtual interface using a number of different protocols/algorithms.

failover    - Sends traffic through the secondary port if the master becomes
              inactive.
fec         - Supports Cisco Fast EtherChannel.
lacp        - Supports the IEEE 802.3ad Link Aggregation Control Protocol
              (LACP) and the Marker Protocol.
loadbalance - Static loadbalancing using an outgoing hash.
roundrobin  - Distributes outgoing traffic using a round-robin scheduler
              through all active ports.

This code was obtained from OpenBSD and this also includes 802.3ad LACP support
from agr(4) in NetBSD.
This commit is contained in:
Andrew Thompson 2007-04-10 00:27:25 +00:00
parent 60dd8da775
commit b47888ceba
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=168561
10 changed files with 4198 additions and 0 deletions

153
sbin/ifconfig/iftrunk.c Normal file
View File

@ -0,0 +1,153 @@
/*-
*/
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_trunk.h>
#include <net/route.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
#include "ifconfig.h"
static void
settrunkport(const char *val, int d, int s, const struct afswtch *afp)
{
struct trunk_reqport rp;
bzero(&rp, sizeof(rp));
strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
if (ioctl(s, SIOCSTRUNKPORT, &rp))
err(1, "SIOCSTRUNKPORT");
}
static void
unsettrunkport(const char *val, int d, int s, const struct afswtch *afp)
{
struct trunk_reqport rp;
bzero(&rp, sizeof(rp));
strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
if (ioctl(s, SIOCSTRUNKDELPORT, &rp))
err(1, "SIOCSTRUNKDELPORT");
}
static void
settrunkproto(const char *val, int d, int s, const struct afswtch *afp)
{
struct trunk_protos tpr[] = TRUNK_PROTOS;
struct trunk_reqall ra;
int i;
bzero(&ra, sizeof(ra));
ra.ra_proto = TRUNK_PROTO_MAX;
for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
if (strcmp(val, tpr[i].tpr_name) == 0) {
ra.ra_proto = tpr[i].tpr_proto;
break;
}
}
if (ra.ra_proto == TRUNK_PROTO_MAX)
errx(1, "Invalid trunk protocol: %s", val);
strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
if (ioctl(s, SIOCSTRUNK, &ra) != 0)
err(1, "SIOCSTRUNK");
}
static void
trunk_status(int s)
{
struct trunk_protos tpr[] = TRUNK_PROTOS;
struct trunk_reqport rp, rpbuf[TRUNK_MAX_PORTS];
struct trunk_reqall ra;
const char *proto = "<unknown>";
int i, isport = 0;
bzero(&rp, sizeof(rp));
bzero(&ra, sizeof(ra));
strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
if (ioctl(s, SIOCGTRUNKPORT, &rp) == 0)
isport = 1;
strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
ra.ra_size = sizeof(rpbuf);
ra.ra_port = rpbuf;
if (ioctl(s, SIOCGTRUNK, &ra) == 0) {
for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
if (ra.ra_proto == tpr[i].tpr_proto) {
proto = tpr[i].tpr_name;
break;
}
}
printf("\ttrunk: trunkproto %s", proto);
if (isport)
printf(" trunkdev %s", rp.rp_ifname);
putchar('\n');
for (i = 0; i < ra.ra_ports; i++) {
printf("\t\ttrunkport %s ", rpbuf[i].rp_portname);
printb("", rpbuf[i].rp_flags, TRUNK_PORT_BITS);
putchar('\n');
}
if (0 /* XXX */) {
printf("\tsupported trunk protocols:\n");
for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++)
printf("\t\ttrunkproto %s\n", tpr[i].tpr_name);
}
} else if (isport)
printf("\ttrunk: trunkdev %s\n", rp.rp_ifname);
}
static struct cmd trunk_cmds[] = {
DEF_CMD_ARG("trunkport", settrunkport),
DEF_CMD_ARG("-trunkport", unsettrunkport),
DEF_CMD_ARG("trunkproto", settrunkproto),
};
static struct afswtch af_trunk = {
.af_name = "af_trunk",
.af_af = AF_UNSPEC,
.af_other_status = trunk_status,
};
static __constructor void
trunk_ctor(void)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
for (i = 0; i < N(trunk_cmds); i++)
cmd_register(&trunk_cmds[i]);
af_register(&af_trunk);
#undef N
}

172
share/man/man4/trunk.4 Normal file
View File

@ -0,0 +1,172 @@
.\" $OpenBSD: trunk.4,v 1.18 2006/06/09 13:53:34 jmc Exp $
.\"
.\" Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.\" $FreeBSD$
.\"
.Dd March 6, 2007
.Dt TRUNK 4
.Os
.Sh NAME
.Nm trunk
.Nd link aggregation and link failover interface
.Sh SYNOPSIS
To compile this driver into the kernel,
place the following line in your
kernel configuration file:
.Bd -ragged -offset indent
.Cd "device trunk"
.Ed
.Pp
Alternatively, to load the driver as a
module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
if_trunk_load="YES"
.Ed
.Sh DESCRIPTION
The
.Nm
interface allows aggregation of multiple network interfaces as one virtual
.Nm
interface for the purpose of providing fault-tolerance and high-speed links.
.Pp
A
.Nm
interface can be created using the
.Ic ifconfig trunk Ns Ar N Ic create
command.
It can use different link aggregation protocols specified
using the
.Ic trunkproto Ar proto
option.
Child interfaces can be added using the
.Ic trunkport Ar child-iface
option and removed using the
.Ic -trunkport Ar child-iface
option.
.Pp
The driver currently supports the trunk protocols
.Ic failover
(the default),
.Ic fec ,
.Ic lacp ,
.Ic loadbalance ,
.Ic roundrobin ,
and
.Ic none .
The protocols determine which ports are used for outgoing traffic
and whether a specific port accepts incoming traffic.
The interface link state is used to validate if the port is active or
not.
.Bl -tag -width loadbalance
.It Ic failover
Sends and receives traffic only through the master port.
If the master port becomes unavailable,
the next active port is used.
The first interface added is the master port;
any interfaces added after that are used as failover devices.
.It Ic fec
Supports Cisco EtherChannel.
This is a static setup and does not negotiate aggregation with the peer or
exchange frames to monitor the link.
.It Ic lacp
Supports the IEEE 802.3ad Link Aggregation Control Protocol (LACP) and the
Marker Protocol.
LACP will negotiate a set of aggregable links with the peer in to one or more
Link Aggregated Groups.
Each LAG is composed of ports of the same speed, set to full-duplex operation.
The traffic will be balanced across the ports in the LAG with the greatest
total speed, in most cases there will only be one LAG which contains all ports.
In the event of changes in physical connectivity, Link Aggregation will quickly
converge to a new configuration.
.It Ic loadbalance
Balances outgoing traffic across the active ports based on hashed
protocol header information and accepts incoming traffic from
any active port.
This is a static setup and does not negotiate aggregation with the peer or
exchange frames to monitor the link.
The hash includes the Ethernet source and destination address, and, if
available, the VLAN tag, and the IP source and destination address.
.It Ic roundrobin
Distributes outgoing traffic using a round-robin scheduler
through all active ports and accepts incoming traffic from
any active port.
.It Ic none
This protocol is intended to do nothing: it disables any traffic without
disabling the
.Nm
interface itself.
.El
.Pp
Each
.Nm
interface is created at runtime using interface cloning.
This is
most easily done with the
.Xr ifconfig 8
.Cm create
command or using the
.Va cloned_interfaces
variable in
.Xr rc.conf 5 .
.Sh EXAMPLES
Create a 802.3ad trunk using LACP with two
.Xr bge 4
Gigabit Ethernet interfaces:
.Bd -literal -offset indent
# ifconfig bge0 up
# ifconfig bge1 up
# ifconfig trunk0 trunkproto lacp trunkport bge0 trunkport bge1 \e
192.168.1.1 netmask 255.255.255.0
.Ed
.Pp
The following example uses an active failover trunk to set up roaming
between wired and wireless networks using two network devices.
Whenever the wired master interface is unplugged, the wireless failover
device will be used:
.Bd -literal -offset indent
# ifconfig em0 up
# ifconfig ath0 nwid my_net up
# ifconfig trunk0 trunkproto failover trunkport em0 trunkport ath0 \e
192.168.1.1 netmask 255.255.255.0
.Ed
.Sh SEE ALSO
.Xr ng_fec 4 ,
.Xr ng_one2many 4 ,
.Xr ifconfig 8
.Sh HISTORY
The
.Nm
device first appeared in
.Fx 7.0 .
.Sh AUTHORS
.An -nosplit
The
.Nm
driver was written by
.An Reyk Floeter Aq reyk@openbsd.org .
The LACP implementation was written by
.An YAMAMOTO Takashi
for
.Nx .
.Sh BUGS
There is no way to configure LACP administrative variables, including system
and port priorities.
The current implementation always performs active-mode LACP and uses 0x8000 as
system and port priorities.
.Pp
WPA security does not currently work correctly with a wireless interface added
to the trunk.

1763
sys/net/ieee8023ad_lacp.c Normal file

File diff suppressed because it is too large Load Diff

289
sys/net/ieee8023ad_lacp.h Normal file
View File

@ -0,0 +1,289 @@
/* $NetBSD: ieee8023ad_impl.h,v 1.2 2005/12/10 23:21:39 elad Exp $ */
/*-
* Copyright (c)2005 YAMAMOTO Takashi,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* IEEE802.3ad LACP
*
* implementation details.
*/
#define LACP_TIMER_CURRENT_WHILE 0
#define LACP_TIMER_PERIODIC 1
#define LACP_TIMER_WAIT_WHILE 2
#define LACP_NTIMER 3
#define LACP_TIMER_ARM(port, timer, val) \
(port)->lp_timer[(timer)] = (val)
#define LACP_TIMER_DISARM(port, timer) \
(port)->lp_timer[(timer)] = 0
#define LACP_TIMER_ISARMED(port, timer) \
((port)->lp_timer[(timer)] > 0)
/*
* IEEE802.3ad LACP
*
* protocol definitions.
*/
#define LACP_STATE_ACTIVITY (1<<0)
#define LACP_STATE_TIMEOUT (1<<1)
#define LACP_STATE_AGGREGATION (1<<2)
#define LACP_STATE_SYNC (1<<3)
#define LACP_STATE_COLLECTING (1<<4)
#define LACP_STATE_DISTRIBUTING (1<<5)
#define LACP_STATE_DEFAULTED (1<<6)
#define LACP_STATE_EXPIRED (1<<7)
#define LACP_PORT_NTT 0x00000001
#define LACP_PORT_PROMISC 0x00000004
#define LACP_PORT_LADDRCHANGED 0x00000008
#define LACP_PORT_ATTACHED 0x00000010
#define LACP_PORT_LARVAL 0x00000020
#define LACP_PORT_DETACHING 0x00000040
#define LACP_STATE_BITS \
"\020" \
"\001ACTIVITY" \
"\002TIMEOUT" \
"\003AGGREGATION" \
"\004SYNC" \
"\005COLLECTING" \
"\006DISTRIBUTING" \
"\007DEFAULTED" \
"\010EXPIRED"
/*
* IEEE802.3 slow protocols
*
* protocol (on-wire) definitions.
*
* XXX should be elsewhere.
*/
#define SLOWPROTOCOLS_SUBTYPE_LACP 1
#define SLOWPROTOCOLS_SUBTYPE_MARKER 2
struct slowprothdr {
uint8_t sph_subtype;
uint8_t sph_version;
} __packed;
/*
* TLV on-wire structure.
*/
struct tlvhdr {
uint8_t tlv_type;
uint8_t tlv_length;
/* uint8_t tlv_value[]; */
} __packed;
/*
* ... and our implementation.
*/
#define TLV_SET(tlv, type, length) \
do { \
(tlv)->tlv_type = (type); \
(tlv)->tlv_length = sizeof(*tlv) + (length); \
} while (/*CONSTCOND*/0)
struct tlv_template {
uint8_t tmpl_type;
uint8_t tmpl_length;
};
struct lacp_systemid {
uint16_t lsi_prio;
uint8_t lsi_mac[6];
} __packed;
struct lacp_portid {
uint16_t lpi_prio;
uint16_t lpi_portno;
} __packed;
struct lacp_peerinfo {
struct lacp_systemid lip_systemid;
uint16_t lip_key;
struct lacp_portid lip_portid;
uint8_t lip_state;
uint8_t lip_resv[3];
} __packed;
struct lacp_collectorinfo {
uint16_t lci_maxdelay;
uint8_t lci_resv[12];
} __packed;
struct lacpdu {
struct ether_header ldu_eh;
struct slowprothdr ldu_sph;
struct tlvhdr ldu_tlv_actor;
struct lacp_peerinfo ldu_actor;
struct tlvhdr ldu_tlv_partner;
struct lacp_peerinfo ldu_partner;
struct tlvhdr ldu_tlv_collector;
struct lacp_collectorinfo ldu_collector;
struct tlvhdr ldu_tlv_term;
uint8_t ldu_resv[50];
} __packed;
#define LACP_TRANSIT_DELAY 1000 /* in msec */
enum lacp_selected {
LACP_UNSELECTED,
LACP_STANDBY, /* not used in this implementation */
LACP_SELECTED,
};
enum lacp_mux_state {
LACP_MUX_DETACHED,
LACP_MUX_WAITING,
LACP_MUX_ATTACHED,
LACP_MUX_COLLECTING,
LACP_MUX_DISTRIBUTING,
};
struct lacp_port {
TAILQ_ENTRY(lacp_port) lp_dist_q;
LIST_ENTRY(lacp_port) lp_next;
struct lacp_softc *lp_lsc;
struct trunk_port *lp_trunk;
struct ifnet *lp_ifp;
struct lacp_peerinfo lp_partner;
struct lacp_peerinfo lp_actor;
#define lp_state lp_actor.lip_state
#define lp_key lp_actor.lip_key
struct timeval lp_last_lacpdu;
int lp_lacpdu_sent;
enum lacp_mux_state lp_mux_state;
enum lacp_selected lp_selected;
int lp_flags;
u_int lp_media; /* XXX redundant */
int lp_timer[LACP_NTIMER];
struct lacp_aggregator *lp_aggregator;
};
struct lacp_aggregator {
TAILQ_ENTRY(lacp_aggregator) la_q;
int la_refcnt; /* num of ports which selected us */
int la_nports; /* num of distributing ports */
TAILQ_HEAD(, lacp_port) la_ports; /* distributing ports */
struct lacp_peerinfo la_partner;
struct lacp_peerinfo la_actor;
int la_pending; /* number of ports which is waiting wait_while */
};
struct lacp_softc {
struct trunk_softc *lsc_trunk;
struct lacp_aggregator *lsc_active_aggregator;
TAILQ_HEAD(, lacp_aggregator) lsc_aggregators;
boolean_t lsc_suppress_distributing;
struct callout lsc_transit_callout;
struct callout lsc_callout;
LIST_HEAD(, lacp_port) lsc_ports;
u_int32_t lsc_hashkey;
};
#define LACP_TYPE_ACTORINFO 1
#define LACP_TYPE_PARTNERINFO 2
#define LACP_TYPE_COLLECTORINFO 3
/* timeout values (in sec) */
#define LACP_FAST_PERIODIC_TIME (1)
#define LACP_SLOW_PERIODIC_TIME (30)
#define LACP_SHORT_TIMEOUT_TIME (3 * LACP_FAST_PERIODIC_TIME)
#define LACP_LONG_TIMEOUT_TIME (3 * LACP_SLOW_PERIODIC_TIME)
#define LACP_CHURN_DETECTION_TIME (60)
#define LACP_AGGREGATE_WAIT_TIME (2)
/*
int tlv_check(const void *, size_t, const struct tlvhdr *,
const struct tlv_template *, boolean_t);
*/
/*
* IEEE802.3ad marker protocol
*
* protocol (on-wire) definitions.
*/
struct markerdu {
struct ether_header mdu_eh;
struct slowprothdr mdu_sph;
struct tlvhdr mdu_tlv;
uint16_t mdu_rq_port;
uint8_t mdu_rq_system[6];
uint8_t mdu_rq_xid[4];
uint8_t mdu_pad[2];
struct tlvhdr mdu_tlv_term;
uint8_t mdu_resv[90];
} __packed;
#define MARKER_TYPE_INFO 1
#define MARKER_TYPE_RESPONSE 2
#define LACP_STATE_EQ(s1, s2, mask) \
((((s1) ^ (s2)) & (mask)) == 0)
#define LACP_PORT(_tp) ((struct lacp_port *)(_tp)->tp_psc)
#define LACP_SOFTC(_tr) ((struct lacp_softc *)(_tr)->tr_psc)
int lacp_input(struct trunk_port *, struct mbuf *);
int lacp_marker_input(struct trunk_port *, struct mbuf *);
struct trunk_port *lacp_select_tx_port(struct trunk_softc *, struct mbuf *);
int lacp_attach(struct trunk_softc *);
int lacp_detach(struct trunk_softc *);
void lacp_init(struct trunk_softc *);
void lacp_stop(struct trunk_softc *);
int lacp_port_create(struct trunk_port *);
void lacp_port_destroy(struct trunk_port *);
void lacp_linkstate(struct trunk_port *);
int lacp_port_isactive(struct trunk_port *);
/* following constants don't include terminating NUL */
#define LACP_MACSTR_MAX (2*6 + 5)
#define LACP_SYSTEMPRIOSTR_MAX (4)
#define LACP_SYSTEMIDSTR_MAX (LACP_SYSTEMPRIOSTR_MAX + 1 + LACP_MACSTR_MAX)
#define LACP_PORTPRIOSTR_MAX (4)
#define LACP_PORTNOSTR_MAX (4)
#define LACP_PORTIDSTR_MAX (LACP_PORTPRIOSTR_MAX + 1 + LACP_PORTNOSTR_MAX)
#define LACP_KEYSTR_MAX (4)
#define LACP_PARTNERSTR_MAX \
(1 + LACP_SYSTEMIDSTR_MAX + 1 + LACP_KEYSTR_MAX + 1 \
+ LACP_PORTIDSTR_MAX + 1)
#define LACP_LAGIDSTR_MAX \
(1 + LACP_PARTNERSTR_MAX + 1 + LACP_PARTNERSTR_MAX + 1)
#define LACP_STATESTR_MAX (255) /* XXX */

View File

@ -96,6 +96,7 @@ SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW,
void (*bstp_linkstate_p)(struct ifnet *ifp, int state);
void (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
void (*trunk_linkstate_p)(struct ifnet *ifp, int state);
struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
@ -1378,6 +1379,10 @@ do_link_state_change(void *arg, int pending)
KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!"));
(*bstp_linkstate_p)(ifp, link_state);
}
if (ifp->if_trunk) {
KASSERT(trunk_linkstate_p != NULL,("if_trunk not loaded!"));
(*trunk_linkstate_p)(ifp, link_state);
}
devctl_notify("IFNET", ifp->if_xname,
(link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN", NULL);
@ -2593,6 +2598,7 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
case IFT_L2VLAN:
case IFT_BRIDGE:
case IFT_ARCNET:
case IFT_IEEE8023ADLAG:
bcopy(lladdr, LLADDR(sdl), len);
break;
default:

View File

@ -113,6 +113,9 @@ int (*bridge_output_p)(struct ifnet *, struct mbuf *,
struct sockaddr *, struct rtentry *);
void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
/* if_trunk(4) support */
struct mbuf *(*trunk_input_p)(struct ifnet *, struct mbuf *);
static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -602,6 +605,17 @@ ether_input(struct ifnet *ifp, struct mbuf *m)
return;
}
/* Handle input from a trunk(4) port */
if (ifp->if_type == IFT_IEEE8023ADLAG) {
KASSERT(trunk_input_p != NULL,
("%s: if_trunk not loaded!", __func__));
m = (*trunk_input_p)(ifp, m);
if (m != NULL)
ifp = m->m_pkthdr.rcvif;
else
return;
}
/*
* If the hardware did not process an 802.1Q tag, do this now,
* to allow 802.1P priority frames to be passed to the main input

1590
sys/net/if_trunk.c Normal file

File diff suppressed because it is too large Load Diff

209
sys/net/if_trunk.h Normal file
View File

@ -0,0 +1,209 @@
/* $OpenBSD: if_trunk.h,v 1.11 2007/01/31 06:20:19 reyk Exp $ */
/*
* Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _NET_TRUNK_H
#define _NET_TRUNK_H
/*
* Global definitions
*/
#define TRUNK_MAX_PORTS 32 /* logically */
#define TRUNK_MAX_NAMESIZE 32 /* name of a protocol */
#define TRUNK_MAX_STACKING 4 /* maximum number of stacked trunks */
/* Port flags */
#define TRUNK_PORT_SLAVE 0x00000000 /* normal enslaved port */
#define TRUNK_PORT_MASTER 0x00000001 /* primary port */
#define TRUNK_PORT_STACK 0x00000002 /* stacked trunk port */
#define TRUNK_PORT_ACTIVE 0x00000004 /* port is active */
#define TRUNK_PORT_COLLECTING 0x00000008 /* port is active */
#define TRUNK_PORT_DISTRIBUTING 0x00000010 /* port is active */
#define TRUNK_PORT_GLOBAL 0x80000000 /* IOCTL: global flag */
#define TRUNK_PORT_BITS "\20\01MASTER\02STACK\03ACTIVE\04COLLECTING" \
"\05DISTRIBUTING"
/* Supported trunk PROTOs */
#define TRUNK_PROTO_NONE 0 /* no trunk protocol defined */
#define TRUNK_PROTO_ROUNDROBIN 1 /* simple round robin */
#define TRUNK_PROTO_FAILOVER 2 /* active failover */
#define TRUNK_PROTO_LOADBALANCE 3 /* loadbalance */
#define TRUNK_PROTO_LACP 4 /* 802.3ad lacp */
#define TRUNK_PROTO_ETHERCHANNEL 5 /* Cisco FEC */
#define TRUNK_PROTO_MAX 6
struct trunk_protos {
const char *tpr_name;
int tpr_proto;
};
#define TRUNK_PROTO_DEFAULT TRUNK_PROTO_FAILOVER
#define TRUNK_PROTOS { \
{ "failover", TRUNK_PROTO_FAILOVER }, \
{ "fec", TRUNK_PROTO_ETHERCHANNEL }, \
{ "lacp", TRUNK_PROTO_LACP }, \
{ "loadbalance", TRUNK_PROTO_LOADBALANCE }, \
{ "roundrobin", TRUNK_PROTO_ROUNDROBIN }, \
{ "none", TRUNK_PROTO_NONE }, \
{ "default", TRUNK_PROTO_DEFAULT } \
}
/*
* Trunk ioctls.
*/
/* Trunk port settings */
struct trunk_reqport {
char rp_ifname[IFNAMSIZ]; /* name of the trunk */
char rp_portname[IFNAMSIZ]; /* name of the port */
u_int32_t rp_prio; /* port priority */
u_int32_t rp_flags; /* port flags */
};
#define SIOCGTRUNKPORT _IOWR('i', 140, struct trunk_reqport)
#define SIOCSTRUNKPORT _IOW('i', 141, struct trunk_reqport)
#define SIOCSTRUNKDELPORT _IOW('i', 142, struct trunk_reqport)
/* Trunk, ports and options */
struct trunk_reqall {
char ra_ifname[IFNAMSIZ]; /* name of the trunk */
u_int ra_proto; /* trunk protocol */
size_t ra_size; /* size of buffer */
struct trunk_reqport *ra_port; /* allocated buffer */
int ra_ports; /* total port count */
};
#define SIOCGTRUNK _IOWR('i', 143, struct trunk_reqall)
#define SIOCSTRUNK _IOW('i', 144, struct trunk_reqall)
#ifdef _KERNEL
/*
* Internal kernel part
*/
#define tp_ifname tp_ifp->if_xname /* interface name */
#define tp_link_state tp_ifp->if_link_state /* link state */
#define tp_capabilities tp_ifp->if_capabilities /* capabilities */
#define TRUNK_PORTACTIVE(_tp) ( \
((_tp)->tp_link_state == LINK_STATE_UP) && \
((_tp)->tp_ifp->if_flags & IFF_UP) \
)
#define mc_enm mc_u.mcu_enm
struct trunk_ifreq {
union {
struct ifreq ifreq;
struct {
char ifr_name[IFNAMSIZ];
struct sockaddr_storage ifr_ss;
} ifreq_storage;
} ifreq;
};
#define tr_ifflags tr_ifp->if_flags /* flags */
#define tr_ifname tr_ifp->if_xname /* name */
#define tr_capabilities tr_ifp->if_capabilities /* capabilities */
#define IFCAP_TRUNK_MASK 0xffff0000 /* private capabilities */
#define IFCAP_TRUNK_FULLDUPLEX 0x00010000 /* full duplex with >1 ports */
/* Private data used by the loadbalancing protocol */
#define TRUNK_LB_MAXKEYS 8
struct trunk_lb {
u_int32_t lb_key;
struct trunk_port *lb_ports[TRUNK_MAX_PORTS];
};
struct trunk_mc {
union {
struct ether_multi *mcu_enm;
} mc_u;
struct sockaddr_storage mc_addr;
SLIST_ENTRY(trunk_mc) mc_entries;
};
struct trunk_softc {
struct ifnet *tr_ifp; /* virtual interface */
struct mtx tr_mtx;
int tr_proto; /* trunk protocol */
u_int tr_count; /* number of ports */
struct trunk_port *tr_primary; /* primary port */
struct ifmedia tr_media; /* media config */
caddr_t tr_psc; /* protocol data */
SLIST_HEAD(__tplhd, trunk_port) tr_ports; /* list of interfaces */
SLIST_ENTRY(trunk_softc) tr_entries;
SLIST_HEAD(__mclhd, trunk_mc) tr_mc_head; /* multicast addresses */
/* Trunk protocol callbacks */
int (*tr_detach)(struct trunk_softc *);
int (*tr_start)(struct trunk_softc *, struct mbuf *);
struct mbuf *(*tr_input)(struct trunk_softc *, struct trunk_port *,
struct mbuf *);
int (*tr_port_create)(struct trunk_port *);
void (*tr_port_destroy)(struct trunk_port *);
void (*tr_linkstate)(struct trunk_port *);
void (*tr_init)(struct trunk_softc *);
void (*tr_stop)(struct trunk_softc *);
void (*tr_lladdr)(struct trunk_softc *);
};
struct trunk_port {
struct ifnet *tp_ifp; /* physical interface */
struct trunk_softc *tp_trunk; /* parent trunk */
uint8_t tp_lladdr[ETHER_ADDR_LEN];
u_char tp_iftype; /* interface type */
uint32_t tp_prio; /* port priority */
uint32_t tp_flags; /* port flags */
int tp_ifflags; /* saved ifp flags */
void *lh_cookie; /* if state hook */
caddr_t tp_psc; /* protocol data */
/* Redirected callbacks */
int (*tp_ioctl)(struct ifnet *, u_long, caddr_t);
int (*tp_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
SLIST_ENTRY(trunk_port) tp_entries;
};
#define TRUNK_LOCK_INIT(_tr) mtx_init(&(_tr)->tr_mtx, "if_trunk", NULL, \
MTX_DEF)
#define TRUNK_LOCK_DESTROY(_tr) mtx_destroy(&(_tr)->tr_mtx)
#define TRUNK_LOCK(_tr) mtx_lock(&(_tr)->tr_mtx)
#define TRUNK_UNLOCK(_tr) mtx_unlock(&(_tr)->tr_mtx)
#define TRUNK_LOCKED(_tr) mtx_owned(&(_tr)->tr_mtx)
#define TRUNK_LOCK_ASSERT(_tr) mtx_assert(&(_tr)->tr_mtx, MA_OWNED)
extern struct mbuf *(*trunk_input_p)(struct ifnet *, struct mbuf *);
extern void (*trunk_linkstate_p)(struct ifnet *, int );
int trunk_enqueue(struct ifnet *, struct mbuf *);
uint32_t trunk_hashmbuf(struct mbuf *, uint32_t);
#endif /* _KERNEL */
#endif /* _NET_TRUNK_H */

View File

@ -186,6 +186,7 @@ struct ifnet {
TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if */
/* protected by if_addr_mtx */
void *if_pf_kif;
void *if_trunk; /* trunk glue */
};
typedef void if_init_f_t(void *);

View File

@ -319,6 +319,7 @@
#define PRIV_NET_IFDESTROY 412 /* Destroy cloned interface. */
#define PRIV_NET_ADDIFADDR 413 /* Add protocol addr to interface. */
#define PRIV_NET_DELIFADDR 414 /* Delete protocol addr on interface. */
#define PRIV_NET_TRUNK 415 /* Administer trunk. */
/*
* 802.11-related privileges.