1 /*	$NetBSD: ieee8023ad_lacp_sm_rx.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_sm_rx.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/ieee8023_slowprotocols.h>
41 #include <net/agr/ieee8023_tlv.h>
42 #include <net/agr/ieee8023ad_lacp.h>
43 #include <net/agr/ieee8023ad_lacp_impl.h>
44 #include <net/agr/ieee8023ad_lacp_sm.h>
45 #include <net/agr/ieee8023ad_lacp_debug.h>
46 
47 /* receive machine */
48 
49 static void lacp_sm_rx_update_ntt(struct lacp_port *, const struct lacpdu *);
50 static void lacp_sm_rx_record_pdu(struct lacp_port *, const struct lacpdu *);
51 static void lacp_sm_rx_update_selected(struct lacp_port *, const struct lacpdu *);
52 
53 static void lacp_sm_rx_record_default(struct lacp_port *);
54 static void lacp_sm_rx_update_default_selected(struct lacp_port *);
55 
56 static void lacp_sm_rx_update_selected_from_peerinfo(struct lacp_port *,
57     const struct lacp_peerinfo *);
58 
59 /*
60  * partner administration variables.
61  * XXX should be configurable.
62  */
63 
64 static const struct lacp_peerinfo lacp_partner_admin = {
65 	.lip_systemid = { .lsi_prio = 0xffff },
66 	.lip_portid = { .lpi_prio = 0xffff },
67 #if 1
68 	/* optimistic */
69 	.lip_state = LACP_STATE_SYNC | LACP_STATE_AGGREGATION |
70 	    LACP_STATE_COLLECTING | LACP_STATE_DISTRIBUTING,
71 #else
72 	/* pessimistic */
73 	.lip_state = 0,
74 #endif
75 };
76 
77 void
lacp_sm_rx(struct lacp_port * lp,const struct lacpdu * du)78 lacp_sm_rx(struct lacp_port *lp, const struct lacpdu *du)
79 {
80 	int timeout;
81 
82 	/*
83 	 * check LACP_DISABLED first
84 	 */
85 
86 	if (!(lp->lp_state & LACP_STATE_AGGREGATION)) {
87 		return;
88 	}
89 
90 	/*
91 	 * check loopback condition.
92 	 */
93 
94 	if (!lacp_compare_systemid(&du->ldu_actor.lip_systemid,
95 	    &lp->lp_actor.lip_systemid)) {
96 		return;
97 	}
98 
99 	/*
100 	 * EXPIRED, DEFAULTED, CURRENT -> CURRENT
101 	 */
102 
103 	lacp_sm_rx_update_selected(lp, du);
104 	lacp_sm_rx_update_ntt(lp, du);
105 	lacp_sm_rx_record_pdu(lp, du);
106 
107 	timeout = (lp->lp_state & LACP_STATE_TIMEOUT) ?
108 	    LACP_SHORT_TIMEOUT_TIME : LACP_LONG_TIMEOUT_TIME;
109 	LACP_TIMER_ARM(lp, LACP_TIMER_CURRENT_WHILE, timeout);
110 
111 	lp->lp_state &= ~LACP_STATE_EXPIRED;
112 
113 	/*
114 	 * kick transmit machine without waiting the next tick.
115 	 */
116 
117 	lacp_sm_tx(lp);
118 }
119 
120 void
lacp_sm_rx_set_expired(struct lacp_port * lp)121 lacp_sm_rx_set_expired(struct lacp_port *lp)
122 {
123 
124 	lp->lp_partner.lip_state &= ~LACP_STATE_SYNC;
125 	lp->lp_partner.lip_state |= LACP_STATE_TIMEOUT;
126 	LACP_TIMER_ARM(lp, LACP_TIMER_CURRENT_WHILE, LACP_SHORT_TIMEOUT_TIME);
127 	lp->lp_state |= LACP_STATE_EXPIRED;
128 }
129 
130 void
lacp_sm_rx_timer(struct lacp_port * lp)131 lacp_sm_rx_timer(struct lacp_port *lp)
132 {
133 
134 	if ((lp->lp_state & LACP_STATE_EXPIRED) == 0) {
135 		/* CURRENT -> EXPIRED */
136 		LACP_DPRINTF((lp, "%s: CURRENT -> EXPIRED\n", __func__));
137 		lacp_sm_rx_set_expired(lp);
138 	} else {
139 		/* EXPIRED -> DEFAULTED */
140 		LACP_DPRINTF((lp, "%s: EXPIRED -> DEFAULTED\n", __func__));
141 		lacp_sm_rx_update_default_selected(lp);
142 		lacp_sm_rx_record_default(lp);
143 		lp->lp_state &= ~LACP_STATE_EXPIRED;
144 	}
145 }
146 
147 static void
lacp_sm_rx_record_pdu(struct lacp_port * lp,const struct lacpdu * du)148 lacp_sm_rx_record_pdu(struct lacp_port *lp, const struct lacpdu *du)
149 {
150 	bool active;
151 	uint8_t oldpstate;
152 #if defined(LACP_DEBUG)
153 	char buf[LACP_STATESTR_MAX+1];
154 #endif
155 
156 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
157 
158 	oldpstate = lp->lp_partner.lip_state;
159 
160 	active = (du->ldu_actor.lip_state & LACP_STATE_ACTIVITY)
161 	    || ((lp->lp_state & LACP_STATE_ACTIVITY) &&
162 	    (du->ldu_partner.lip_state & LACP_STATE_ACTIVITY));
163 
164 	lp->lp_partner = du->ldu_actor;
165 	if (active &&
166 	    ((LACP_STATE_EQ(lp->lp_state, du->ldu_partner.lip_state,
167 	    LACP_STATE_AGGREGATION) &&
168 	    !lacp_compare_peerinfo(&lp->lp_actor, &du->ldu_partner))
169 	    || (du->ldu_partner.lip_state & LACP_STATE_AGGREGATION) == 0)) {
170 		/* nothing */
171 	} else {
172 		lp->lp_partner.lip_state &= ~LACP_STATE_SYNC;
173 	}
174 
175 	lp->lp_state &= ~LACP_STATE_DEFAULTED;
176 
177 	LACP_DPRINTF((lp, "old pstate %s\n",
178 	    lacp_format_state(oldpstate, buf, sizeof(buf))));
179 	LACP_DPRINTF((lp, "new pstate %s\n",
180 	    lacp_format_state(lp->lp_partner.lip_state, buf, sizeof(buf))));
181 
182 	lacp_sm_ptx_update_timeout(lp, oldpstate);
183 }
184 
185 static void
lacp_sm_rx_update_ntt(struct lacp_port * lp,const struct lacpdu * du)186 lacp_sm_rx_update_ntt(struct lacp_port *lp, const struct lacpdu *du)
187 {
188 
189 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
190 
191 	if (lacp_compare_peerinfo(&lp->lp_actor, &du->ldu_partner) ||
192 	    !LACP_STATE_EQ(lp->lp_state, du->ldu_partner.lip_state,
193 	    LACP_STATE_ACTIVITY | LACP_STATE_SYNC | LACP_STATE_AGGREGATION)) {
194 		LACP_DPRINTF((lp, "%s: assert ntt\n", __func__));
195 		lacp_sm_assert_ntt(lp);
196 	}
197 }
198 
199 static void
lacp_sm_rx_record_default(struct lacp_port * lp)200 lacp_sm_rx_record_default(struct lacp_port *lp)
201 {
202 	uint8_t oldpstate;
203 
204 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
205 
206 	oldpstate = lp->lp_partner.lip_state;
207 	lp->lp_partner = lacp_partner_admin;
208 	lp->lp_state |= LACP_STATE_DEFAULTED;
209 	lacp_sm_ptx_update_timeout(lp, oldpstate);
210 }
211 
212 static void
lacp_sm_rx_update_selected_from_peerinfo(struct lacp_port * lp,const struct lacp_peerinfo * info)213 lacp_sm_rx_update_selected_from_peerinfo(struct lacp_port *lp,
214     const struct lacp_peerinfo *info)
215 {
216 
217 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
218 
219 	if (lacp_compare_peerinfo(&lp->lp_partner, info) ||
220 	    !LACP_STATE_EQ(lp->lp_partner.lip_state, info->lip_state,
221 	    LACP_STATE_AGGREGATION)) {
222 		lp->lp_selected = LACP_UNSELECTED;
223 		/* mux machine will clean up lp->lp_aggregator */
224 	}
225 }
226 
227 static void
lacp_sm_rx_update_selected(struct lacp_port * lp,const struct lacpdu * du)228 lacp_sm_rx_update_selected(struct lacp_port *lp, const struct lacpdu *du)
229 {
230 
231 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
232 
233 	lacp_sm_rx_update_selected_from_peerinfo(lp, &du->ldu_actor);
234 }
235 
236 static void
lacp_sm_rx_update_default_selected(struct lacp_port * lp)237 lacp_sm_rx_update_default_selected(struct lacp_port *lp)
238 {
239 
240 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
241 
242 	lacp_sm_rx_update_selected_from_peerinfo(lp, &lacp_partner_admin);
243 }
244