1 /* $NetBSD: ieee8023ad_lacp_select.c,v 1.4 2007/02/21 23:00:07 thorpej Exp $ */
4 * Copyright (c)2005 YAMAMOTO Takashi,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
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 $");
32 #include <sys/param.h>
33 #include <sys/callout.h>
35 #include <sys/systm.h>
38 #include <net/if_ether.h>
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>
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
*);
59 static struct lacp_aggregator
*lacp_aggregator_get(struct lacp_softc
*,
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
*);
67 lacp_aggregator_addref(struct lacp_softc
*lsc
, struct lacp_aggregator
*la
)
69 #if defined(LACP_DEBUG)
70 char buf
[LACP_LAGIDSTR_MAX
+1];
73 LACP_DPRINTF((NULL
, "%s: lagid=%s, refcnt %d -> %d\n",
75 lacp_format_lagid(&la
->la_actor
, &la
->la_partner
,
77 la
->la_refcnt
, la
->la_refcnt
+ 1));
79 KASSERT(la
->la_refcnt
> 0);
81 KASSERT(la
->la_refcnt
> la
->la_nports
);
85 lacp_aggregator_delref(struct lacp_softc
*lsc
, struct lacp_aggregator
*la
)
87 #if defined(LACP_DEBUG)
88 char buf
[LACP_LAGIDSTR_MAX
+1];
91 LACP_DPRINTF((NULL
, "%s: lagid=%s, refcnt %d -> %d\n",
93 lacp_format_lagid(&la
->la_actor
, &la
->la_partner
,
95 la
->la_refcnt
, la
->la_refcnt
- 1));
97 KASSERT(la
->la_refcnt
> la
->la_nports
);
99 if (la
->la_refcnt
> 0) {
103 KASSERT(la
->la_refcnt
== 0);
104 KASSERT(lsc
->lsc_active_aggregator
!= la
);
106 TAILQ_REMOVE(&lsc
->lsc_aggregators
, la
, la_q
);
112 * lacp_aggregator_get: allocate an aggregator.
115 static struct lacp_aggregator
*
116 lacp_aggregator_get(struct lacp_softc
*lsc
, struct lacp_port
*lp
)
118 struct lacp_aggregator
*la
;
120 la
= malloc(sizeof(*la
), M_DEVBUF
, M_NOWAIT
);
124 TAILQ_INIT(&la
->la_ports
);
126 TAILQ_INSERT_TAIL(&lsc
->lsc_aggregators
, la
, la_q
);
133 * lacp_fill_aggregator_id: setup a newly allocated aggregator from a port.
137 lacp_fill_aggregator_id(struct lacp_aggregator
*la
, const struct lacp_port
*lp
)
140 lacp_fill_aggregator_id_peer(&la
->la_partner
, &lp
->lp_partner
);
141 lacp_fill_aggregator_id_peer(&la
->la_actor
, &lp
->lp_actor
);
143 la
->la_actor
.lip_state
= lp
->lp_state
& LACP_STATE_AGGREGATION
;
147 lacp_fill_aggregator_id_peer(struct lacp_peerinfo
*lpi_aggr
,
148 const struct lacp_peerinfo
*lpi_port
)
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
;
157 * lacp_aggregator_is_compatible: check if a port can join to an aggregator.
161 lacp_aggregator_is_compatible(const struct lacp_aggregator
*la
,
162 const struct lacp_port
*lp
)
165 if (!(lp
->lp_state
& LACP_STATE_AGGREGATION
) ||
166 !(lp
->lp_partner
.lip_state
& LACP_STATE_AGGREGATION
)) {
170 if (!(la
->la_actor
.lip_state
& LACP_STATE_AGGREGATION
)) {
174 if (!lacp_peerinfo_is_compatible(&la
->la_partner
, &lp
->lp_partner
)) {
178 if (!lacp_peerinfo_is_compatible(&la
->la_actor
, &lp
->lp_actor
)) {
186 lacp_peerinfo_is_compatible(const struct lacp_peerinfo
*a
,
187 const struct lacp_peerinfo
*b
)
190 if (memcmp(&a
->lip_systemid
, &b
->lip_systemid
,
191 sizeof(a
->lip_systemid
))) {
195 if (memcmp(&a
->lip_key
, &b
->lip_key
, sizeof(a
->lip_key
))) {
203 * lacp_select: select an aggregator. create one if necessary.
207 lacp_select(struct lacp_port
*lp
)
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];
215 if (lp
->lp_aggregator
) {
219 KASSERT(!LACP_TIMER_ISARMED(lp
, LACP_TIMER_WAIT_WHILE
));
221 LACP_DPRINTF((lp
, "port lagid=%s\n",
222 lacp_format_lagid(&lp
->lp_actor
, &lp
->lp_partner
,
225 TAILQ_FOREACH(la
, &lsc
->lsc_aggregators
, la_q
) {
226 if (lacp_aggregator_is_compatible(la
, lp
)) {
232 la
= lacp_aggregator_get(lsc
, lp
);
234 LACP_DPRINTF((lp
, "aggregator creation failed\n"));
237 * will retry on the next tick.
242 lacp_fill_aggregator_id(la
, lp
);
243 LACP_DPRINTF((lp
, "aggregator created\n"));
245 LACP_DPRINTF((lp
, "compatible aggregator found\n"));
246 lacp_aggregator_addref(lsc
, la
);
249 LACP_DPRINTF((lp
, "aggregator lagid=%s\n",
250 lacp_format_lagid(&la
->la_actor
, &la
->la_partner
,
253 lp
->lp_aggregator
= la
;
254 lp
->lp_selected
= LACP_SELECTED
;
258 * lacp_unselect: finish unselect/detach process.
262 lacp_unselect(struct lacp_port
*lp
)
264 struct lacp_softc
*lsc
= LACP_SOFTC(AGR_SC_FROM_PORT(lp
->lp_agrport
));
265 struct lacp_aggregator
*la
= lp
->lp_aggregator
;
267 KASSERT(!LACP_TIMER_ISARMED(lp
, LACP_TIMER_WAIT_WHILE
));
273 lp
->lp_aggregator
= NULL
;
274 lacp_aggregator_delref(lsc
, la
);