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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 | |