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:
parent
60dd8da775
commit
b47888ceba
153
sbin/ifconfig/iftrunk.c
Normal file
153
sbin/ifconfig/iftrunk.c
Normal 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
172
share/man/man4/trunk.4
Normal 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
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
289
sys/net/ieee8023ad_lacp.h
Normal 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 */
|
@ -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:
|
||||
|
@ -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
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
209
sys/net/if_trunk.h
Normal 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 */
|
@ -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 *);
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user