Home | History | Annotate | Line # | Download | only in agr
ieee8023ad_lacp_select.c revision 1.4
      1 /*	$NetBSD: ieee8023ad_lacp_select.c,v 1.4 2007/02/21 23:00:07 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c)2005 YAMAMOTO Takashi,
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: ieee8023ad_lacp_select.c,v 1.4 2007/02/21 23:00:07 thorpej Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/callout.h>
     34 #include <sys/mbuf.h>
     35 #include <sys/systm.h>
     36 
     37 #include <net/if.h>
     38 #include <net/if_ether.h>
     39 
     40 #include <net/agr/if_agrvar_impl.h>
     41 #include <net/agr/ieee8023_slowprotocols.h>
     42 #include <net/agr/ieee8023_tlv.h>
     43 #include <net/agr/ieee8023ad_lacp.h>
     44 #include <net/agr/ieee8023ad_lacp_impl.h>
     45 #include <net/agr/ieee8023ad_impl.h>
     46 #include <net/agr/ieee8023ad_lacp_debug.h>
     47 
     48 /* selection logic */
     49 
     50 static void lacp_fill_aggregator_id(struct lacp_aggregator *,
     51     const struct lacp_port *);
     52 static void lacp_fill_aggregator_id_peer(struct lacp_peerinfo *,
     53     const struct lacp_peerinfo *);
     54 static bool lacp_aggregator_is_compatible(const struct lacp_aggregator *,
     55     const struct lacp_port *);
     56 static bool lacp_peerinfo_is_compatible(const struct lacp_peerinfo *,
     57     const struct lacp_peerinfo *);
     58 
     59 static struct lacp_aggregator *lacp_aggregator_get(struct lacp_softc *,
     60     struct lacp_port *);
     61 static void lacp_aggregator_addref(struct lacp_softc *,
     62     struct lacp_aggregator *);
     63 static void lacp_aggregator_delref(struct lacp_softc *,
     64     struct lacp_aggregator *);
     65 
     66 static void
     67 lacp_aggregator_addref(struct lacp_softc *lsc, struct lacp_aggregator *la)
     68 {
     69 #if defined(LACP_DEBUG)
     70 	char buf[LACP_LAGIDSTR_MAX+1];
     71 #endif
     72 
     73 	LACP_DPRINTF((NULL, "%s: lagid=%s, refcnt %d -> %d\n",
     74 	    __func__,
     75 	    lacp_format_lagid(&la->la_actor, &la->la_partner,
     76 	    buf, sizeof(buf)),
     77 	    la->la_refcnt, la->la_refcnt + 1));
     78 
     79 	KASSERT(la->la_refcnt > 0);
     80 	la->la_refcnt++;
     81 	KASSERT(la->la_refcnt > la->la_nports);
     82 }
     83 
     84 static void
     85 lacp_aggregator_delref(struct lacp_softc *lsc, struct lacp_aggregator *la)
     86 {
     87 #if defined(LACP_DEBUG)
     88 	char buf[LACP_LAGIDSTR_MAX+1];
     89 #endif
     90 
     91 	LACP_DPRINTF((NULL, "%s: lagid=%s, refcnt %d -> %d\n",
     92 	    __func__,
     93 	    lacp_format_lagid(&la->la_actor, &la->la_partner,
     94 	    buf, sizeof(buf)),
     95 	    la->la_refcnt, la->la_refcnt - 1));
     96 
     97 	KASSERT(la->la_refcnt > la->la_nports);
     98 	la->la_refcnt--;
     99 	if (la->la_refcnt > 0) {
    100 		return;
    101 	}
    102 
    103 	KASSERT(la->la_refcnt == 0);
    104 	KASSERT(lsc->lsc_active_aggregator != la);
    105 
    106 	TAILQ_REMOVE(&lsc->lsc_aggregators, la, la_q);
    107 
    108 	free(la, M_DEVBUF);
    109 }
    110 
    111 /*
    112  * lacp_aggregator_get: allocate an aggregator.
    113  */
    114 
    115 static struct lacp_aggregator *
    116 lacp_aggregator_get(struct lacp_softc *lsc, struct lacp_port *lp)
    117 {
    118 	struct lacp_aggregator *la;
    119 
    120 	la = malloc(sizeof(*la), M_DEVBUF, M_NOWAIT);
    121 	if (la) {
    122 		la->la_refcnt = 1;
    123 		la->la_nports = 0;
    124 		TAILQ_INIT(&la->la_ports);
    125 		la->la_pending = 0;
    126 		TAILQ_INSERT_TAIL(&lsc->lsc_aggregators, la, la_q);
    127 	}
    128 
    129 	return la;
    130 }
    131 
    132 /*
    133  * lacp_fill_aggregator_id: setup a newly allocated aggregator from a port.
    134  */
    135 
    136 static void
    137 lacp_fill_aggregator_id(struct lacp_aggregator *la, const struct lacp_port *lp)
    138 {
    139 
    140 	lacp_fill_aggregator_id_peer(&la->la_partner, &lp->lp_partner);
    141 	lacp_fill_aggregator_id_peer(&la->la_actor, &lp->lp_actor);
    142 
    143 	la->la_actor.lip_state = lp->lp_state & LACP_STATE_AGGREGATION;
    144 }
    145 
    146 static void
    147 lacp_fill_aggregator_id_peer(struct lacp_peerinfo *lpi_aggr,
    148     const struct lacp_peerinfo *lpi_port)
    149 {
    150 
    151 	memset(lpi_aggr, 0, sizeof(*lpi_aggr));
    152 	lpi_aggr->lip_systemid = lpi_port->lip_systemid;
    153 	lpi_aggr->lip_key = lpi_port->lip_key;
    154 }
    155 
    156 /*
    157  * lacp_aggregator_is_compatible: check if a port can join to an aggregator.
    158  */
    159 
    160 static bool
    161 lacp_aggregator_is_compatible(const struct lacp_aggregator *la,
    162     const struct lacp_port *lp)
    163 {
    164 
    165 	if (!(lp->lp_state & LACP_STATE_AGGREGATION) ||
    166 	    !(lp->lp_partner.lip_state & LACP_STATE_AGGREGATION)) {
    167 		return FALSE;
    168 	}
    169 
    170 	if (!(la->la_actor.lip_state & LACP_STATE_AGGREGATION)) {
    171 		return FALSE;
    172 	}
    173 
    174 	if (!lacp_peerinfo_is_compatible(&la->la_partner, &lp->lp_partner)) {
    175 		return FALSE;
    176 	}
    177 
    178 	if (!lacp_peerinfo_is_compatible(&la->la_actor, &lp->lp_actor)) {
    179 		return FALSE;
    180 	}
    181 
    182 	return TRUE;
    183 }
    184 
    185 static bool
    186 lacp_peerinfo_is_compatible(const struct lacp_peerinfo *a,
    187     const struct lacp_peerinfo *b)
    188 {
    189 
    190 	if (memcmp(&a->lip_systemid, &b->lip_systemid,
    191 	    sizeof(a->lip_systemid))) {
    192 		return FALSE;
    193 	}
    194 
    195 	if (memcmp(&a->lip_key, &b->lip_key, sizeof(a->lip_key))) {
    196 		return FALSE;
    197 	}
    198 
    199 	return TRUE;
    200 }
    201 
    202 /*
    203  * lacp_select: select an aggregator.  create one if necessary.
    204  */
    205 
    206 void
    207 lacp_select(struct lacp_port *lp)
    208 {
    209 	struct lacp_softc *lsc = LACP_SOFTC(AGR_SC_FROM_PORT(lp->lp_agrport));
    210 	struct lacp_aggregator *la;
    211 #if defined(LACP_DEBUG)
    212 	char buf[LACP_LAGIDSTR_MAX+1];
    213 #endif
    214 
    215 	if (lp->lp_aggregator) {
    216 		return;
    217 	}
    218 
    219 	KASSERT(!LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE));
    220 
    221 	LACP_DPRINTF((lp, "port lagid=%s\n",
    222 	    lacp_format_lagid(&lp->lp_actor, &lp->lp_partner,
    223 	    buf, sizeof(buf))));
    224 
    225 	TAILQ_FOREACH(la, &lsc->lsc_aggregators, la_q) {
    226 		if (lacp_aggregator_is_compatible(la, lp)) {
    227 			break;
    228 		}
    229 	}
    230 
    231 	if (la == NULL) {
    232 		la = lacp_aggregator_get(lsc, lp);
    233 		if (la == NULL) {
    234 			LACP_DPRINTF((lp, "aggregator creation failed\n"));
    235 
    236 			/*
    237 			 * will retry on the next tick.
    238 			 */
    239 
    240 			return;
    241 		}
    242 		lacp_fill_aggregator_id(la, lp);
    243 		LACP_DPRINTF((lp, "aggregator created\n"));
    244 	} else {
    245 		LACP_DPRINTF((lp, "compatible aggregator found\n"));
    246 		lacp_aggregator_addref(lsc, la);
    247 	}
    248 
    249 	LACP_DPRINTF((lp, "aggregator lagid=%s\n",
    250 	    lacp_format_lagid(&la->la_actor, &la->la_partner,
    251 	    buf, sizeof(buf))));
    252 
    253 	lp->lp_aggregator = la;
    254 	lp->lp_selected = LACP_SELECTED;
    255 }
    256 
    257 /*
    258  * lacp_unselect: finish unselect/detach process.
    259  */
    260 
    261 void
    262 lacp_unselect(struct lacp_port *lp)
    263 {
    264 	struct lacp_softc *lsc = LACP_SOFTC(AGR_SC_FROM_PORT(lp->lp_agrport));
    265 	struct lacp_aggregator *la = lp->lp_aggregator;
    266 
    267 	KASSERT(!LACP_TIMER_ISARMED(lp, LACP_TIMER_WAIT_WHILE));
    268 
    269 	if (la == NULL) {
    270 		return;
    271 	}
    272 
    273 	lp->lp_aggregator = NULL;
    274 	lacp_aggregator_delref(lsc, la);
    275 }
    276