1 |
1275 |
phoenix |
/*
|
2 |
|
|
* Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
|
3 |
|
|
*
|
4 |
|
|
* This program is free software; you can redistribute it and/or modify it
|
5 |
|
|
* under the terms of the GNU General Public License as published by the Free
|
6 |
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
7 |
|
|
* any later version.
|
8 |
|
|
*
|
9 |
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
10 |
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
11 |
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
12 |
|
|
* more details.
|
13 |
|
|
*
|
14 |
|
|
* You should have received a copy of the GNU General Public License along with
|
15 |
|
|
* this program; if not, write to the Free Software Foundation, Inc., 59
|
16 |
|
|
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
17 |
|
|
*
|
18 |
|
|
* The full GNU General Public License is included in this distribution in the
|
19 |
|
|
* file called LICENSE.
|
20 |
|
|
*
|
21 |
|
|
*
|
22 |
|
|
* Changes:
|
23 |
|
|
*
|
24 |
|
|
* 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
|
25 |
|
|
* Amir Noam <amir.noam at intel dot com>
|
26 |
|
|
* - Added support for lacp_rate module param.
|
27 |
|
|
*
|
28 |
|
|
* 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
|
29 |
|
|
* - Based on discussion on mailing list, changed locking scheme
|
30 |
|
|
* to use lock/unlock or lock_bh/unlock_bh appropriately instead
|
31 |
|
|
* of lock_irqsave/unlock_irqrestore. The new scheme helps exposing
|
32 |
|
|
* hidden bugs and solves system hangs that occurred due to the fact
|
33 |
|
|
* that holding lock_irqsave doesn't prevent softirqs from running.
|
34 |
|
|
* This also increases total throughput since interrupts are not
|
35 |
|
|
* blocked on each transmitted packets or monitor timeout.
|
36 |
|
|
*
|
37 |
|
|
* 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
|
38 |
|
|
* - Renamed bond_3ad_link_status_changed() to
|
39 |
|
|
* bond_3ad_handle_link_change() for compatibility with TLB.
|
40 |
|
|
*
|
41 |
|
|
* 2003/05/20 - Amir Noam <amir.noam at intel dot com>
|
42 |
|
|
* - Fix long fail over time when releasing last slave of an active
|
43 |
|
|
* aggregator - send LACPDU on unbind of slave to tell partner this
|
44 |
|
|
* port is no longer aggregatable.
|
45 |
|
|
*
|
46 |
|
|
* 2003/06/25 - Tsippy Mendelson <tsippy.mendelson at intel dot com>
|
47 |
|
|
* - Send LACPDU as highest priority packet to further fix the above
|
48 |
|
|
* problem on very high Tx traffic load where packets may get dropped
|
49 |
|
|
* by the slave.
|
50 |
|
|
*
|
51 |
|
|
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
|
52 |
|
|
* - Code cleanup and style changes
|
53 |
|
|
*/
|
54 |
|
|
|
55 |
|
|
//#define BONDING_DEBUG 1
|
56 |
|
|
|
57 |
|
|
#include <linux/skbuff.h>
|
58 |
|
|
#include <linux/if_ether.h>
|
59 |
|
|
#include <linux/netdevice.h>
|
60 |
|
|
#include <linux/spinlock.h>
|
61 |
|
|
#include <linux/ethtool.h>
|
62 |
|
|
#include <linux/if_bonding.h>
|
63 |
|
|
#include <linux/pkt_sched.h>
|
64 |
|
|
#include "bonding.h"
|
65 |
|
|
#include "bond_3ad.h"
|
66 |
|
|
|
67 |
|
|
// General definitions
|
68 |
|
|
#define AD_SHORT_TIMEOUT 1
|
69 |
|
|
#define AD_LONG_TIMEOUT 0
|
70 |
|
|
#define AD_STANDBY 0x2
|
71 |
|
|
#define AD_MAX_TX_IN_SECOND 3
|
72 |
|
|
#define AD_COLLECTOR_MAX_DELAY 0
|
73 |
|
|
|
74 |
|
|
// Timer definitions(43.4.4 in the 802.3ad standard)
|
75 |
|
|
#define AD_FAST_PERIODIC_TIME 1
|
76 |
|
|
#define AD_SLOW_PERIODIC_TIME 30
|
77 |
|
|
#define AD_SHORT_TIMEOUT_TIME (3*AD_FAST_PERIODIC_TIME)
|
78 |
|
|
#define AD_LONG_TIMEOUT_TIME (3*AD_SLOW_PERIODIC_TIME)
|
79 |
|
|
#define AD_CHURN_DETECTION_TIME 60
|
80 |
|
|
#define AD_AGGREGATE_WAIT_TIME 2
|
81 |
|
|
|
82 |
|
|
// Port state definitions(43.4.2.2 in the 802.3ad standard)
|
83 |
|
|
#define AD_STATE_LACP_ACTIVITY 0x1
|
84 |
|
|
#define AD_STATE_LACP_TIMEOUT 0x2
|
85 |
|
|
#define AD_STATE_AGGREGATION 0x4
|
86 |
|
|
#define AD_STATE_SYNCHRONIZATION 0x8
|
87 |
|
|
#define AD_STATE_COLLECTING 0x10
|
88 |
|
|
#define AD_STATE_DISTRIBUTING 0x20
|
89 |
|
|
#define AD_STATE_DEFAULTED 0x40
|
90 |
|
|
#define AD_STATE_EXPIRED 0x80
|
91 |
|
|
|
92 |
|
|
// Port Variables definitions used by the State Machines(43.4.7 in the 802.3ad standard)
|
93 |
|
|
#define AD_PORT_BEGIN 0x1
|
94 |
|
|
#define AD_PORT_LACP_ENABLED 0x2
|
95 |
|
|
#define AD_PORT_ACTOR_CHURN 0x4
|
96 |
|
|
#define AD_PORT_PARTNER_CHURN 0x8
|
97 |
|
|
#define AD_PORT_READY 0x10
|
98 |
|
|
#define AD_PORT_READY_N 0x20
|
99 |
|
|
#define AD_PORT_MATCHED 0x40
|
100 |
|
|
#define AD_PORT_STANDBY 0x80
|
101 |
|
|
#define AD_PORT_SELECTED 0x100
|
102 |
|
|
#define AD_PORT_MOVED 0x200
|
103 |
|
|
|
104 |
|
|
// Port Key definitions
|
105 |
|
|
// key is determined according to the link speed, duplex and
|
106 |
|
|
// user key(which is yet not supported)
|
107 |
|
|
// ------------------------------------------------------------
|
108 |
|
|
// Port key : | User key | Speed |Duplex|
|
109 |
|
|
// ------------------------------------------------------------
|
110 |
|
|
// 16 6 1 0
|
111 |
|
|
#define AD_DUPLEX_KEY_BITS 0x1
|
112 |
|
|
#define AD_SPEED_KEY_BITS 0x3E
|
113 |
|
|
#define AD_USER_KEY_BITS 0xFFC0
|
114 |
|
|
|
115 |
|
|
//dalloun
|
116 |
|
|
#define AD_LINK_SPEED_BITMASK_1MBPS 0x1
|
117 |
|
|
#define AD_LINK_SPEED_BITMASK_10MBPS 0x2
|
118 |
|
|
#define AD_LINK_SPEED_BITMASK_100MBPS 0x4
|
119 |
|
|
#define AD_LINK_SPEED_BITMASK_1000MBPS 0x8
|
120 |
|
|
//endalloun
|
121 |
|
|
|
122 |
|
|
// compare MAC addresses
|
123 |
|
|
#define MAC_ADDRESS_COMPARE(A, B) memcmp(A, B, ETH_ALEN)
|
124 |
|
|
|
125 |
|
|
static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}};
|
126 |
|
|
static u16 ad_ticks_per_sec;
|
127 |
|
|
static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;
|
128 |
|
|
|
129 |
|
|
// ================= 3AD api to bonding and kernel code ==================
|
130 |
|
|
static u16 __get_link_speed(struct port *port);
|
131 |
|
|
static u8 __get_duplex(struct port *port);
|
132 |
|
|
static inline void __initialize_port_locks(struct port *port);
|
133 |
|
|
static inline void __deinitialize_port_locks(struct port *port);
|
134 |
|
|
//conversions
|
135 |
|
|
static void __ntohs_lacpdu(struct lacpdu *lacpdu);
|
136 |
|
|
static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
|
137 |
|
|
|
138 |
|
|
|
139 |
|
|
// ================= ad code helper functions ==================
|
140 |
|
|
//needed by ad_rx_machine(...)
|
141 |
|
|
static void __record_pdu(struct lacpdu *lacpdu, struct port *port);
|
142 |
|
|
static void __record_default(struct port *port);
|
143 |
|
|
static void __update_selected(struct lacpdu *lacpdu, struct port *port);
|
144 |
|
|
static void __update_default_selected(struct port *port);
|
145 |
|
|
static void __choose_matched(struct lacpdu *lacpdu, struct port *port);
|
146 |
|
|
static void __update_ntt(struct lacpdu *lacpdu, struct port *port);
|
147 |
|
|
|
148 |
|
|
//needed for ad_mux_machine(..)
|
149 |
|
|
static void __attach_bond_to_agg(struct port *port);
|
150 |
|
|
static void __detach_bond_from_agg(struct port *port);
|
151 |
|
|
static int __agg_ports_are_ready(struct aggregator *aggregator);
|
152 |
|
|
static void __set_agg_ports_ready(struct aggregator *aggregator, int val);
|
153 |
|
|
|
154 |
|
|
//needed for ad_agg_selection_logic(...)
|
155 |
|
|
static u32 __get_agg_bandwidth(struct aggregator *aggregator);
|
156 |
|
|
static struct aggregator *__get_active_agg(struct aggregator *aggregator);
|
157 |
|
|
|
158 |
|
|
|
159 |
|
|
// ================= main 802.3ad protocol functions ==================
|
160 |
|
|
static int ad_lacpdu_send(struct port *port);
|
161 |
|
|
static int ad_marker_send(struct port *port, struct marker *marker);
|
162 |
|
|
static void ad_mux_machine(struct port *port);
|
163 |
|
|
static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port);
|
164 |
|
|
static void ad_tx_machine(struct port *port);
|
165 |
|
|
static void ad_periodic_machine(struct port *port);
|
166 |
|
|
static void ad_port_selection_logic(struct port *port);
|
167 |
|
|
static void ad_agg_selection_logic(struct aggregator *aggregator);
|
168 |
|
|
static void ad_clear_agg(struct aggregator *aggregator);
|
169 |
|
|
static void ad_initialize_agg(struct aggregator *aggregator);
|
170 |
|
|
static void ad_initialize_port(struct port *port, int lacp_fast);
|
171 |
|
|
static void ad_initialize_lacpdu(struct lacpdu *Lacpdu);
|
172 |
|
|
static void ad_enable_collecting_distributing(struct port *port);
|
173 |
|
|
static void ad_disable_collecting_distributing(struct port *port);
|
174 |
|
|
static void ad_marker_info_received(struct marker *marker_info, struct port *port);
|
175 |
|
|
static void ad_marker_response_received(struct marker *marker, struct port *port);
|
176 |
|
|
|
177 |
|
|
|
178 |
|
|
/////////////////////////////////////////////////////////////////////////////////
|
179 |
|
|
// ================= api to bonding and kernel code ==================
|
180 |
|
|
/////////////////////////////////////////////////////////////////////////////////
|
181 |
|
|
|
182 |
|
|
/**
|
183 |
|
|
* __get_bond_by_port - get the port's bonding struct
|
184 |
|
|
* @port: the port we're looking at
|
185 |
|
|
*
|
186 |
|
|
* Return @port's bonding struct, or %NULL if it can't be found.
|
187 |
|
|
*/
|
188 |
|
|
static inline struct bonding *__get_bond_by_port(struct port *port)
|
189 |
|
|
{
|
190 |
|
|
if (port->slave == NULL) {
|
191 |
|
|
return NULL;
|
192 |
|
|
}
|
193 |
|
|
|
194 |
|
|
return bond_get_bond_by_slave(port->slave);
|
195 |
|
|
}
|
196 |
|
|
|
197 |
|
|
/**
|
198 |
|
|
* __get_first_port - get the first port in the bond
|
199 |
|
|
* @bond: the bond we're looking at
|
200 |
|
|
*
|
201 |
|
|
* Return the port of the first slave in @bond, or %NULL if it can't be found.
|
202 |
|
|
*/
|
203 |
|
|
static inline struct port *__get_first_port(struct bonding *bond)
|
204 |
|
|
{
|
205 |
|
|
if (bond->slave_cnt == 0) {
|
206 |
|
|
return NULL;
|
207 |
|
|
}
|
208 |
|
|
|
209 |
|
|
return &(SLAVE_AD_INFO(bond->first_slave).port);
|
210 |
|
|
}
|
211 |
|
|
|
212 |
|
|
/**
|
213 |
|
|
* __get_next_port - get the next port in the bond
|
214 |
|
|
* @port: the port we're looking at
|
215 |
|
|
*
|
216 |
|
|
* Return the port of the slave that is next in line of @port's slave in the
|
217 |
|
|
* bond, or %NULL if it can't be found.
|
218 |
|
|
*/
|
219 |
|
|
static inline struct port *__get_next_port(struct port *port)
|
220 |
|
|
{
|
221 |
|
|
struct bonding *bond = __get_bond_by_port(port);
|
222 |
|
|
struct slave *slave = port->slave;
|
223 |
|
|
|
224 |
|
|
// If there's no bond for this port, or this is the last slave
|
225 |
|
|
if ((bond == NULL) || (slave->next == bond->first_slave)) {
|
226 |
|
|
return NULL;
|
227 |
|
|
}
|
228 |
|
|
|
229 |
|
|
return &(SLAVE_AD_INFO(slave->next).port);
|
230 |
|
|
}
|
231 |
|
|
|
232 |
|
|
/**
|
233 |
|
|
* __get_first_agg - get the first aggregator in the bond
|
234 |
|
|
* @bond: the bond we're looking at
|
235 |
|
|
*
|
236 |
|
|
* Return the aggregator of the first slave in @bond, or %NULL if it can't be
|
237 |
|
|
* found.
|
238 |
|
|
*/
|
239 |
|
|
static inline struct aggregator *__get_first_agg(struct port *port)
|
240 |
|
|
{
|
241 |
|
|
struct bonding *bond = __get_bond_by_port(port);
|
242 |
|
|
|
243 |
|
|
// If there's no bond for this port, or bond has no slaves
|
244 |
|
|
if ((bond == NULL) || (bond->slave_cnt == 0)) {
|
245 |
|
|
return NULL;
|
246 |
|
|
}
|
247 |
|
|
|
248 |
|
|
return &(SLAVE_AD_INFO(bond->first_slave).aggregator);
|
249 |
|
|
}
|
250 |
|
|
|
251 |
|
|
/**
|
252 |
|
|
* __get_next_agg - get the next aggregator in the bond
|
253 |
|
|
* @aggregator: the aggregator we're looking at
|
254 |
|
|
*
|
255 |
|
|
* Return the aggregator of the slave that is next in line of @aggregator's
|
256 |
|
|
* slave in the bond, or %NULL if it can't be found.
|
257 |
|
|
*/
|
258 |
|
|
static inline struct aggregator *__get_next_agg(struct aggregator *aggregator)
|
259 |
|
|
{
|
260 |
|
|
struct slave *slave = aggregator->slave;
|
261 |
|
|
struct bonding *bond = bond_get_bond_by_slave(slave);
|
262 |
|
|
|
263 |
|
|
// If there's no bond for this aggregator, or this is the last slave
|
264 |
|
|
if ((bond == NULL) || (slave->next == bond->first_slave)) {
|
265 |
|
|
return NULL;
|
266 |
|
|
}
|
267 |
|
|
|
268 |
|
|
return &(SLAVE_AD_INFO(slave->next).aggregator);
|
269 |
|
|
}
|
270 |
|
|
|
271 |
|
|
/**
|
272 |
|
|
* __disable_port - disable the port's slave
|
273 |
|
|
* @port: the port we're looking at
|
274 |
|
|
*
|
275 |
|
|
*/
|
276 |
|
|
static inline void __disable_port(struct port *port)
|
277 |
|
|
{
|
278 |
|
|
bond_set_slave_inactive_flags(port->slave);
|
279 |
|
|
}
|
280 |
|
|
|
281 |
|
|
/**
|
282 |
|
|
* __enable_port - enable the port's slave, if it's up
|
283 |
|
|
* @port: the port we're looking at
|
284 |
|
|
*
|
285 |
|
|
*/
|
286 |
|
|
static inline void __enable_port(struct port *port)
|
287 |
|
|
{
|
288 |
|
|
struct slave *slave = port->slave;
|
289 |
|
|
|
290 |
|
|
if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev)) {
|
291 |
|
|
bond_set_slave_active_flags(slave);
|
292 |
|
|
}
|
293 |
|
|
}
|
294 |
|
|
|
295 |
|
|
/**
|
296 |
|
|
* __port_is_enabled - check if the port's slave is in active state
|
297 |
|
|
* @port: the port we're looking at
|
298 |
|
|
*
|
299 |
|
|
*/
|
300 |
|
|
static inline int __port_is_enabled(struct port *port)
|
301 |
|
|
{
|
302 |
|
|
return(port->slave->state == BOND_STATE_ACTIVE);
|
303 |
|
|
}
|
304 |
|
|
|
305 |
|
|
/**
|
306 |
|
|
* __get_agg_selection_mode - get the aggregator selection mode
|
307 |
|
|
* @port: the port we're looking at
|
308 |
|
|
*
|
309 |
|
|
* Get the aggregator selection mode. Can be %BANDWIDTH or %COUNT.
|
310 |
|
|
*/
|
311 |
|
|
static inline u32 __get_agg_selection_mode(struct port *port)
|
312 |
|
|
{
|
313 |
|
|
struct bonding *bond = __get_bond_by_port(port);
|
314 |
|
|
|
315 |
|
|
if (bond == NULL) {
|
316 |
|
|
return AD_BANDWIDTH;
|
317 |
|
|
}
|
318 |
|
|
|
319 |
|
|
return BOND_AD_INFO(bond).agg_select_mode;
|
320 |
|
|
}
|
321 |
|
|
|
322 |
|
|
/**
|
323 |
|
|
* __check_agg_selection_timer - check if the selection timer has expired
|
324 |
|
|
* @port: the port we're looking at
|
325 |
|
|
*
|
326 |
|
|
*/
|
327 |
|
|
static inline int __check_agg_selection_timer(struct port *port)
|
328 |
|
|
{
|
329 |
|
|
struct bonding *bond = __get_bond_by_port(port);
|
330 |
|
|
|
331 |
|
|
if (bond == NULL) {
|
332 |
|
|
return 0;
|
333 |
|
|
}
|
334 |
|
|
|
335 |
|
|
return BOND_AD_INFO(bond).agg_select_timer ? 1 : 0;
|
336 |
|
|
}
|
337 |
|
|
|
338 |
|
|
/**
|
339 |
|
|
* __get_rx_machine_lock - lock the port's RX machine
|
340 |
|
|
* @port: the port we're looking at
|
341 |
|
|
*
|
342 |
|
|
*/
|
343 |
|
|
static inline void __get_rx_machine_lock(struct port *port)
|
344 |
|
|
{
|
345 |
|
|
spin_lock(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
|
346 |
|
|
}
|
347 |
|
|
|
348 |
|
|
/**
|
349 |
|
|
* __release_rx_machine_lock - unlock the port's RX machine
|
350 |
|
|
* @port: the port we're looking at
|
351 |
|
|
*
|
352 |
|
|
*/
|
353 |
|
|
static inline void __release_rx_machine_lock(struct port *port)
|
354 |
|
|
{
|
355 |
|
|
spin_unlock(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
|
356 |
|
|
}
|
357 |
|
|
|
358 |
|
|
/**
|
359 |
|
|
* __get_link_speed - get a port's speed
|
360 |
|
|
* @port: the port we're looking at
|
361 |
|
|
*
|
362 |
|
|
* Return @port's speed in 802.3ad bitmask format. i.e. one of:
|
363 |
|
|
* 0,
|
364 |
|
|
* %AD_LINK_SPEED_BITMASK_10MBPS,
|
365 |
|
|
* %AD_LINK_SPEED_BITMASK_100MBPS,
|
366 |
|
|
* %AD_LINK_SPEED_BITMASK_1000MBPS
|
367 |
|
|
*/
|
368 |
|
|
static u16 __get_link_speed(struct port *port)
|
369 |
|
|
{
|
370 |
|
|
struct slave *slave = port->slave;
|
371 |
|
|
u16 speed;
|
372 |
|
|
|
373 |
|
|
/* this if covers only a special case: when the configuration starts with
|
374 |
|
|
* link down, it sets the speed to 0.
|
375 |
|
|
* This is done in spite of the fact that the e100 driver reports 0 to be
|
376 |
|
|
* compatible with MVT in the future.*/
|
377 |
|
|
if (slave->link != BOND_LINK_UP) {
|
378 |
|
|
speed=0;
|
379 |
|
|
} else {
|
380 |
|
|
switch (slave->speed) {
|
381 |
|
|
case SPEED_10:
|
382 |
|
|
speed = AD_LINK_SPEED_BITMASK_10MBPS;
|
383 |
|
|
break;
|
384 |
|
|
|
385 |
|
|
case SPEED_100:
|
386 |
|
|
speed = AD_LINK_SPEED_BITMASK_100MBPS;
|
387 |
|
|
break;
|
388 |
|
|
|
389 |
|
|
case SPEED_1000:
|
390 |
|
|
speed = AD_LINK_SPEED_BITMASK_1000MBPS;
|
391 |
|
|
break;
|
392 |
|
|
|
393 |
|
|
default:
|
394 |
|
|
speed = 0; // unknown speed value from ethtool. shouldn't happen
|
395 |
|
|
break;
|
396 |
|
|
}
|
397 |
|
|
}
|
398 |
|
|
|
399 |
|
|
dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed);
|
400 |
|
|
return speed;
|
401 |
|
|
}
|
402 |
|
|
|
403 |
|
|
/**
|
404 |
|
|
* __get_duplex - get a port's duplex
|
405 |
|
|
* @port: the port we're looking at
|
406 |
|
|
*
|
407 |
|
|
* Return @port's duplex in 802.3ad bitmask format. i.e.:
|
408 |
|
|
* 0x01 if in full duplex
|
409 |
|
|
* 0x00 otherwise
|
410 |
|
|
*/
|
411 |
|
|
static u8 __get_duplex(struct port *port)
|
412 |
|
|
{
|
413 |
|
|
struct slave *slave = port->slave;
|
414 |
|
|
|
415 |
|
|
u8 retval;
|
416 |
|
|
|
417 |
|
|
// handling a special case: when the configuration starts with
|
418 |
|
|
// link down, it sets the duplex to 0.
|
419 |
|
|
if (slave->link != BOND_LINK_UP) {
|
420 |
|
|
retval=0x0;
|
421 |
|
|
} else {
|
422 |
|
|
switch (slave->duplex) {
|
423 |
|
|
case DUPLEX_FULL:
|
424 |
|
|
retval=0x1;
|
425 |
|
|
dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number);
|
426 |
|
|
break;
|
427 |
|
|
case DUPLEX_HALF:
|
428 |
|
|
default:
|
429 |
|
|
retval=0x0;
|
430 |
|
|
dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number);
|
431 |
|
|
break;
|
432 |
|
|
}
|
433 |
|
|
}
|
434 |
|
|
return retval;
|
435 |
|
|
}
|
436 |
|
|
|
437 |
|
|
/**
|
438 |
|
|
* __initialize_port_locks - initialize a port's RX machine spinlock
|
439 |
|
|
* @port: the port we're looking at
|
440 |
|
|
*
|
441 |
|
|
*/
|
442 |
|
|
static inline void __initialize_port_locks(struct port *port)
|
443 |
|
|
{
|
444 |
|
|
// make sure it isn't called twice
|
445 |
|
|
spin_lock_init(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
|
446 |
|
|
}
|
447 |
|
|
|
448 |
|
|
/**
|
449 |
|
|
* __deinitialize_port_locks - deinitialize a port's RX machine spinlock
|
450 |
|
|
* @port: the port we're looking at
|
451 |
|
|
*
|
452 |
|
|
*/
|
453 |
|
|
static inline void __deinitialize_port_locks(struct port *port)
|
454 |
|
|
{
|
455 |
|
|
}
|
456 |
|
|
|
457 |
|
|
//conversions
|
458 |
|
|
/**
|
459 |
|
|
* __ntohs_lacpdu - convert the contents of a LACPDU to host byte order
|
460 |
|
|
* @lacpdu: the speicifed lacpdu
|
461 |
|
|
*
|
462 |
|
|
* For each multi-byte field in the lacpdu, convert its content
|
463 |
|
|
*/
|
464 |
|
|
static void __ntohs_lacpdu(struct lacpdu *lacpdu)
|
465 |
|
|
{
|
466 |
|
|
if (lacpdu) {
|
467 |
|
|
lacpdu->actor_system_priority = ntohs(lacpdu->actor_system_priority);
|
468 |
|
|
lacpdu->actor_key = ntohs(lacpdu->actor_key);
|
469 |
|
|
lacpdu->actor_port_priority = ntohs(lacpdu->actor_port_priority);
|
470 |
|
|
lacpdu->actor_port = ntohs(lacpdu->actor_port);
|
471 |
|
|
lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority);
|
472 |
|
|
lacpdu->partner_key = ntohs(lacpdu->partner_key);
|
473 |
|
|
lacpdu->partner_port_priority = ntohs(lacpdu->partner_port_priority);
|
474 |
|
|
lacpdu->partner_port = ntohs(lacpdu->partner_port);
|
475 |
|
|
lacpdu->collector_max_delay = ntohs(lacpdu->collector_max_delay);
|
476 |
|
|
}
|
477 |
|
|
}
|
478 |
|
|
|
479 |
|
|
/**
|
480 |
|
|
* __ad_timer_to_ticks - convert a given timer type to AD module ticks
|
481 |
|
|
* @timer_type: which timer to operate
|
482 |
|
|
* @par: timer parameter. see below
|
483 |
|
|
*
|
484 |
|
|
* If @timer_type is %current_while_timer, @par indicates long/short timer.
|
485 |
|
|
* If @timer_type is %periodic_timer, @par is one of %FAST_PERIODIC_TIME,
|
486 |
|
|
* %SLOW_PERIODIC_TIME.
|
487 |
|
|
*/
|
488 |
|
|
static u16 __ad_timer_to_ticks(u16 timer_type, u16 par)
|
489 |
|
|
{
|
490 |
|
|
u16 retval=0; //to silence the compiler
|
491 |
|
|
|
492 |
|
|
switch (timer_type) {
|
493 |
|
|
case AD_CURRENT_WHILE_TIMER: // for rx machine usage
|
494 |
|
|
if (par) { // for short or long timeout
|
495 |
|
|
retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec); // short timeout
|
496 |
|
|
} else {
|
497 |
|
|
retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec); // long timeout
|
498 |
|
|
}
|
499 |
|
|
break;
|
500 |
|
|
case AD_ACTOR_CHURN_TIMER: // for local churn machine
|
501 |
|
|
retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec);
|
502 |
|
|
break;
|
503 |
|
|
case AD_PERIODIC_TIMER: // for periodic machine
|
504 |
|
|
retval = (par*ad_ticks_per_sec); // long timeout
|
505 |
|
|
break;
|
506 |
|
|
case AD_PARTNER_CHURN_TIMER: // for remote churn machine
|
507 |
|
|
retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec);
|
508 |
|
|
break;
|
509 |
|
|
case AD_WAIT_WHILE_TIMER: // for selection machine
|
510 |
|
|
retval = (AD_AGGREGATE_WAIT_TIME*ad_ticks_per_sec);
|
511 |
|
|
break;
|
512 |
|
|
}
|
513 |
|
|
return retval;
|
514 |
|
|
}
|
515 |
|
|
|
516 |
|
|
|
517 |
|
|
/////////////////////////////////////////////////////////////////////////////////
|
518 |
|
|
// ================= ad_rx_machine helper functions ==================
|
519 |
|
|
/////////////////////////////////////////////////////////////////////////////////
|
520 |
|
|
|
521 |
|
|
/**
|
522 |
|
|
* __record_pdu - record parameters from a received lacpdu
|
523 |
|
|
* @lacpdu: the lacpdu we've received
|
524 |
|
|
* @port: the port we're looking at
|
525 |
|
|
*
|
526 |
|
|
* Record the parameter values for the Actor carried in a received lacpdu as
|
527 |
|
|
* the current partner operational parameter values and sets
|
528 |
|
|
* actor_oper_port_state.defaulted to FALSE.
|
529 |
|
|
*/
|
530 |
|
|
static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
|
531 |
|
|
{
|
532 |
|
|
// validate lacpdu and port
|
533 |
|
|
if (lacpdu && port) {
|
534 |
|
|
// record the new parameter values for the partner operational
|
535 |
|
|
port->partner_oper_port_number = lacpdu->actor_port;
|
536 |
|
|
port->partner_oper_port_priority = lacpdu->actor_port_priority;
|
537 |
|
|
port->partner_oper_system = lacpdu->actor_system;
|
538 |
|
|
port->partner_oper_system_priority = lacpdu->actor_system_priority;
|
539 |
|
|
port->partner_oper_key = lacpdu->actor_key;
|
540 |
|
|
// zero partener's lase states
|
541 |
|
|
port->partner_oper_port_state = 0;
|
542 |
|
|
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY);
|
543 |
|
|
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_TIMEOUT);
|
544 |
|
|
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_AGGREGATION);
|
545 |
|
|
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION);
|
546 |
|
|
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_COLLECTING);
|
547 |
|
|
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DISTRIBUTING);
|
548 |
|
|
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DEFAULTED);
|
549 |
|
|
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_EXPIRED);
|
550 |
|
|
|
551 |
|
|
// set actor_oper_port_state.defaulted to FALSE
|
552 |
|
|
port->actor_oper_port_state &= ~AD_STATE_DEFAULTED;
|
553 |
|
|
|
554 |
|
|
// set the partner sync. to on if the partner is sync. and the port is matched
|
555 |
|
|
if ((port->sm_vars & AD_PORT_MATCHED) && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) {
|
556 |
|
|
port->partner_oper_port_state |= AD_STATE_SYNCHRONIZATION;
|
557 |
|
|
} else {
|
558 |
|
|
port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
|
559 |
|
|
}
|
560 |
|
|
}
|
561 |
|
|
}
|
562 |
|
|
|
563 |
|
|
/**
|
564 |
|
|
* __record_default - record default parameters
|
565 |
|
|
* @port: the port we're looking at
|
566 |
|
|
*
|
567 |
|
|
* This function records the default parameter values for the partner carried
|
568 |
|
|
* in the Partner Admin parameters as the current partner operational parameter
|
569 |
|
|
* values and sets actor_oper_port_state.defaulted to TRUE.
|
570 |
|
|
*/
|
571 |
|
|
static void __record_default(struct port *port)
|
572 |
|
|
{
|
573 |
|
|
// validate the port
|
574 |
|
|
if (port) {
|
575 |
|
|
// record the partner admin parameters
|
576 |
|
|
port->partner_oper_port_number = port->partner_admin_port_number;
|
577 |
|
|
port->partner_oper_port_priority = port->partner_admin_port_priority;
|
578 |
|
|
port->partner_oper_system = port->partner_admin_system;
|
579 |
|
|
port->partner_oper_system_priority = port->partner_admin_system_priority;
|
580 |
|
|
port->partner_oper_key = port->partner_admin_key;
|
581 |
|
|
port->partner_oper_port_state = port->partner_admin_port_state;
|
582 |
|
|
|
583 |
|
|
// set actor_oper_port_state.defaulted to true
|
584 |
|
|
port->actor_oper_port_state |= AD_STATE_DEFAULTED;
|
585 |
|
|
}
|
586 |
|
|
}
|
587 |
|
|
|
588 |
|
|
/**
|
589 |
|
|
* __update_selected - update a port's Selected variable from a received lacpdu
|
590 |
|
|
* @lacpdu: the lacpdu we've received
|
591 |
|
|
* @port: the port we're looking at
|
592 |
|
|
*
|
593 |
|
|
* Update the value of the selected variable, using parameter values from a
|
594 |
|
|
* newly received lacpdu. The parameter values for the Actor carried in the
|
595 |
|
|
* received PDU are compared with the corresponding operational parameter
|
596 |
|
|
* values for the ports partner. If one or more of the comparisons shows that
|
597 |
|
|
* the value(s) received in the PDU differ from the current operational values,
|
598 |
|
|
* then selected is set to FALSE and actor_oper_port_state.synchronization is
|
599 |
|
|
* set to out_of_sync. Otherwise, selected remains unchanged.
|
600 |
|
|
*/
|
601 |
|
|
static void __update_selected(struct lacpdu *lacpdu, struct port *port)
|
602 |
|
|
{
|
603 |
|
|
// validate lacpdu and port
|
604 |
|
|
if (lacpdu && port) {
|
605 |
|
|
// check if any parameter is different
|
606 |
|
|
if ((lacpdu->actor_port != port->partner_oper_port_number) ||
|
607 |
|
|
(lacpdu->actor_port_priority != port->partner_oper_port_priority) ||
|
608 |
|
|
MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) ||
|
609 |
|
|
(lacpdu->actor_system_priority != port->partner_oper_system_priority) ||
|
610 |
|
|
(lacpdu->actor_key != port->partner_oper_key) ||
|
611 |
|
|
((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
|
612 |
|
|
) {
|
613 |
|
|
// update the state machine Selected variable
|
614 |
|
|
port->sm_vars &= ~AD_PORT_SELECTED;
|
615 |
|
|
}
|
616 |
|
|
}
|
617 |
|
|
}
|
618 |
|
|
|
619 |
|
|
/**
|
620 |
|
|
* __update_default_selected - update a port's Selected variable from Partner
|
621 |
|
|
* @port: the port we're looking at
|
622 |
|
|
*
|
623 |
|
|
* This function updates the value of the selected variable, using the partner
|
624 |
|
|
* administrative parameter values. The administrative values are compared with
|
625 |
|
|
* the corresponding operational parameter values for the partner. If one or
|
626 |
|
|
* more of the comparisons shows that the administrative value(s) differ from
|
627 |
|
|
* the current operational values, then Selected is set to FALSE and
|
628 |
|
|
* actor_oper_port_state.synchronization is set to OUT_OF_SYNC. Otherwise,
|
629 |
|
|
* Selected remains unchanged.
|
630 |
|
|
*/
|
631 |
|
|
static void __update_default_selected(struct port *port)
|
632 |
|
|
{
|
633 |
|
|
// validate the port
|
634 |
|
|
if (port) {
|
635 |
|
|
// check if any parameter is different
|
636 |
|
|
if ((port->partner_admin_port_number != port->partner_oper_port_number) ||
|
637 |
|
|
(port->partner_admin_port_priority != port->partner_oper_port_priority) ||
|
638 |
|
|
MAC_ADDRESS_COMPARE(&(port->partner_admin_system), &(port->partner_oper_system)) ||
|
639 |
|
|
(port->partner_admin_system_priority != port->partner_oper_system_priority) ||
|
640 |
|
|
(port->partner_admin_key != port->partner_oper_key) ||
|
641 |
|
|
((port->partner_admin_port_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
|
642 |
|
|
) {
|
643 |
|
|
// update the state machine Selected variable
|
644 |
|
|
port->sm_vars &= ~AD_PORT_SELECTED;
|
645 |
|
|
}
|
646 |
|
|
}
|
647 |
|
|
}
|
648 |
|
|
|
649 |
|
|
/**
|
650 |
|
|
* __choose_matched - update a port's matched variable from a received lacpdu
|
651 |
|
|
* @lacpdu: the lacpdu we've received
|
652 |
|
|
* @port: the port we're looking at
|
653 |
|
|
*
|
654 |
|
|
* Update the value of the matched variable, using parameter values from a
|
655 |
|
|
* newly received lacpdu. Parameter values for the partner carried in the
|
656 |
|
|
* received PDU are compared with the corresponding operational parameter
|
657 |
|
|
* values for the actor. Matched is set to TRUE if all of these parameters
|
658 |
|
|
* match and the PDU parameter partner_state.aggregation has the same value as
|
659 |
|
|
* actor_oper_port_state.aggregation and lacp will actively maintain the link
|
660 |
|
|
* in the aggregation. Matched is also set to TRUE if the value of
|
661 |
|
|
* actor_state.aggregation in the received PDU is set to FALSE, i.e., indicates
|
662 |
|
|
* an individual link and lacp will actively maintain the link. Otherwise,
|
663 |
|
|
* matched is set to FALSE. LACP is considered to be actively maintaining the
|
664 |
|
|
* link if either the PDU's actor_state.lacp_activity variable is TRUE or both
|
665 |
|
|
* the actor's actor_oper_port_state.lacp_activity and the PDU's
|
666 |
|
|
* partner_state.lacp_activity variables are TRUE.
|
667 |
|
|
*/
|
668 |
|
|
static void __choose_matched(struct lacpdu *lacpdu, struct port *port)
|
669 |
|
|
{
|
670 |
|
|
// validate lacpdu and port
|
671 |
|
|
if (lacpdu && port) {
|
672 |
|
|
// check if all parameters are alike
|
673 |
|
|
if (((lacpdu->partner_port == port->actor_port_number) &&
|
674 |
|
|
(lacpdu->partner_port_priority == port->actor_port_priority) &&
|
675 |
|
|
!MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) &&
|
676 |
|
|
(lacpdu->partner_system_priority == port->actor_system_priority) &&
|
677 |
|
|
(lacpdu->partner_key == port->actor_oper_port_key) &&
|
678 |
|
|
((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) ||
|
679 |
|
|
// or this is individual link(aggregation == FALSE)
|
680 |
|
|
((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0)
|
681 |
|
|
) {
|
682 |
|
|
// update the state machine Matched variable
|
683 |
|
|
port->sm_vars |= AD_PORT_MATCHED;
|
684 |
|
|
} else {
|
685 |
|
|
port->sm_vars &= ~AD_PORT_MATCHED;
|
686 |
|
|
}
|
687 |
|
|
}
|
688 |
|
|
}
|
689 |
|
|
|
690 |
|
|
/**
|
691 |
|
|
* __update_ntt - update a port's ntt variable from a received lacpdu
|
692 |
|
|
* @lacpdu: the lacpdu we've received
|
693 |
|
|
* @port: the port we're looking at
|
694 |
|
|
*
|
695 |
|
|
* Updates the value of the ntt variable, using parameter values from a newly
|
696 |
|
|
* received lacpdu. The parameter values for the partner carried in the
|
697 |
|
|
* received PDU are compared with the corresponding operational parameter
|
698 |
|
|
* values for the Actor. If one or more of the comparisons shows that the
|
699 |
|
|
* value(s) received in the PDU differ from the current operational values,
|
700 |
|
|
* then ntt is set to TRUE. Otherwise, ntt remains unchanged.
|
701 |
|
|
*/
|
702 |
|
|
static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
|
703 |
|
|
{
|
704 |
|
|
// validate lacpdu and port
|
705 |
|
|
if (lacpdu && port) {
|
706 |
|
|
// check if any parameter is different
|
707 |
|
|
if ((lacpdu->partner_port != port->actor_port_number) ||
|
708 |
|
|
(lacpdu->partner_port_priority != port->actor_port_priority) ||
|
709 |
|
|
MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) ||
|
710 |
|
|
(lacpdu->partner_system_priority != port->actor_system_priority) ||
|
711 |
|
|
(lacpdu->partner_key != port->actor_oper_port_key) ||
|
712 |
|
|
((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) ||
|
713 |
|
|
((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) ||
|
714 |
|
|
((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) ||
|
715 |
|
|
((lacpdu->partner_state & AD_STATE_AGGREGATION) != (port->actor_oper_port_state & AD_STATE_AGGREGATION))
|
716 |
|
|
) {
|
717 |
|
|
// set ntt to be TRUE
|
718 |
|
|
port->ntt = 1;
|
719 |
|
|
}
|
720 |
|
|
}
|
721 |
|
|
}
|
722 |
|
|
|
723 |
|
|
/**
|
724 |
|
|
* __attach_bond_to_agg
|
725 |
|
|
* @port: the port we're looking at
|
726 |
|
|
*
|
727 |
|
|
* Handle the attaching of the port's control parser/multiplexer and the
|
728 |
|
|
* aggregator. This function does nothing since the parser/multiplexer of the
|
729 |
|
|
* receive and the parser/multiplexer of the aggregator are already combined.
|
730 |
|
|
*/
|
731 |
|
|
static void __attach_bond_to_agg(struct port *port)
|
732 |
|
|
{
|
733 |
|
|
port=NULL; // just to satisfy the compiler
|
734 |
|
|
// This function does nothing since the parser/multiplexer of the receive
|
735 |
|
|
// and the parser/multiplexer of the aggregator are already combined
|
736 |
|
|
}
|
737 |
|
|
|
738 |
|
|
/**
|
739 |
|
|
* __detach_bond_from_agg
|
740 |
|
|
* @port: the port we're looking at
|
741 |
|
|
*
|
742 |
|
|
* Handle the detaching of the port's control parser/multiplexer from the
|
743 |
|
|
* aggregator. This function does nothing since the parser/multiplexer of the
|
744 |
|
|
* receive and the parser/multiplexer of the aggregator are already combined.
|
745 |
|
|
*/
|
746 |
|
|
static void __detach_bond_from_agg(struct port *port)
|
747 |
|
|
{
|
748 |
|
|
port=NULL; // just to satisfy the compiler
|
749 |
|
|
// This function does nothing sience the parser/multiplexer of the receive
|
750 |
|
|
// and the parser/multiplexer of the aggregator are already combined
|
751 |
|
|
}
|
752 |
|
|
|
753 |
|
|
/**
|
754 |
|
|
* __agg_ports_are_ready - check if all ports in an aggregator are ready
|
755 |
|
|
* @aggregator: the aggregator we're looking at
|
756 |
|
|
*
|
757 |
|
|
*/
|
758 |
|
|
static int __agg_ports_are_ready(struct aggregator *aggregator)
|
759 |
|
|
{
|
760 |
|
|
struct port *port;
|
761 |
|
|
int retval = 1;
|
762 |
|
|
|
763 |
|
|
if (aggregator) {
|
764 |
|
|
// scan all ports in this aggregator to verfy if they are all ready
|
765 |
|
|
for (port=aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
|
766 |
|
|
if (!(port->sm_vars & AD_PORT_READY_N)) {
|
767 |
|
|
retval = 0;
|
768 |
|
|
break;
|
769 |
|
|
}
|
770 |
|
|
}
|
771 |
|
|
}
|
772 |
|
|
|
773 |
|
|
return retval;
|
774 |
|
|
}
|
775 |
|
|
|
776 |
|
|
/**
|
777 |
|
|
* __set_agg_ports_ready - set value of Ready bit in all ports of an aggregator
|
778 |
|
|
* @aggregator: the aggregator we're looking at
|
779 |
|
|
* @val: Should the ports' ready bit be set on or off
|
780 |
|
|
*
|
781 |
|
|
*/
|
782 |
|
|
static void __set_agg_ports_ready(struct aggregator *aggregator, int val)
|
783 |
|
|
{
|
784 |
|
|
struct port *port;
|
785 |
|
|
|
786 |
|
|
for (port=aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
|
787 |
|
|
if (val) {
|
788 |
|
|
port->sm_vars |= AD_PORT_READY;
|
789 |
|
|
} else {
|
790 |
|
|
port->sm_vars &= ~AD_PORT_READY;
|
791 |
|
|
}
|
792 |
|
|
}
|
793 |
|
|
}
|
794 |
|
|
|
795 |
|
|
/**
|
796 |
|
|
* __get_agg_bandwidth - get the total bandwidth of an aggregator
|
797 |
|
|
* @aggregator: the aggregator we're looking at
|
798 |
|
|
*
|
799 |
|
|
*/
|
800 |
|
|
static u32 __get_agg_bandwidth(struct aggregator *aggregator)
|
801 |
|
|
{
|
802 |
|
|
u32 bandwidth=0;
|
803 |
|
|
u32 basic_speed;
|
804 |
|
|
|
805 |
|
|
if (aggregator->num_of_ports) {
|
806 |
|
|
basic_speed = __get_link_speed(aggregator->lag_ports);
|
807 |
|
|
switch (basic_speed) {
|
808 |
|
|
case AD_LINK_SPEED_BITMASK_1MBPS:
|
809 |
|
|
bandwidth = aggregator->num_of_ports;
|
810 |
|
|
break;
|
811 |
|
|
case AD_LINK_SPEED_BITMASK_10MBPS:
|
812 |
|
|
bandwidth = aggregator->num_of_ports * 10;
|
813 |
|
|
break;
|
814 |
|
|
case AD_LINK_SPEED_BITMASK_100MBPS:
|
815 |
|
|
bandwidth = aggregator->num_of_ports * 100;
|
816 |
|
|
break;
|
817 |
|
|
case AD_LINK_SPEED_BITMASK_1000MBPS:
|
818 |
|
|
bandwidth = aggregator->num_of_ports * 1000;
|
819 |
|
|
break;
|
820 |
|
|
default:
|
821 |
|
|
bandwidth=0; // to silent the compilor ....
|
822 |
|
|
}
|
823 |
|
|
}
|
824 |
|
|
return bandwidth;
|
825 |
|
|
}
|
826 |
|
|
|
827 |
|
|
/**
|
828 |
|
|
* __get_active_agg - get the current active aggregator
|
829 |
|
|
* @aggregator: the aggregator we're looking at
|
830 |
|
|
*
|
831 |
|
|
*/
|
832 |
|
|
static struct aggregator *__get_active_agg(struct aggregator *aggregator)
|
833 |
|
|
{
|
834 |
|
|
struct aggregator *retval = NULL;
|
835 |
|
|
|
836 |
|
|
for (; aggregator; aggregator = __get_next_agg(aggregator)) {
|
837 |
|
|
if (aggregator->is_active) {
|
838 |
|
|
retval = aggregator;
|
839 |
|
|
break;
|
840 |
|
|
}
|
841 |
|
|
}
|
842 |
|
|
|
843 |
|
|
return retval;
|
844 |
|
|
}
|
845 |
|
|
|
846 |
|
|
/**
|
847 |
|
|
* __update_lacpdu_from_port - update a port's lacpdu fields
|
848 |
|
|
* @port: the port we're looking at
|
849 |
|
|
*
|
850 |
|
|
*/
|
851 |
|
|
static inline void __update_lacpdu_from_port(struct port *port)
|
852 |
|
|
{
|
853 |
|
|
struct lacpdu *lacpdu = &port->lacpdu;
|
854 |
|
|
|
855 |
|
|
/* update current actual Actor parameters */
|
856 |
|
|
/* lacpdu->subtype initialized
|
857 |
|
|
* lacpdu->version_number initialized
|
858 |
|
|
* lacpdu->tlv_type_actor_info initialized
|
859 |
|
|
* lacpdu->actor_information_length initialized
|
860 |
|
|
*/
|
861 |
|
|
|
862 |
|
|
lacpdu->actor_system_priority = port->actor_system_priority;
|
863 |
|
|
lacpdu->actor_system = port->actor_system;
|
864 |
|
|
lacpdu->actor_key = port->actor_oper_port_key;
|
865 |
|
|
lacpdu->actor_port_priority = port->actor_port_priority;
|
866 |
|
|
lacpdu->actor_port = port->actor_port_number;
|
867 |
|
|
lacpdu->actor_state = port->actor_oper_port_state;
|
868 |
|
|
|
869 |
|
|
/* lacpdu->reserved_3_1 initialized
|
870 |
|
|
* lacpdu->tlv_type_partner_info initialized
|
871 |
|
|
* lacpdu->partner_information_length initialized
|
872 |
|
|
*/
|
873 |
|
|
|
874 |
|
|
lacpdu->partner_system_priority = port->partner_oper_system_priority;
|
875 |
|
|
lacpdu->partner_system = port->partner_oper_system;
|
876 |
|
|
lacpdu->partner_key = port->partner_oper_key;
|
877 |
|
|
lacpdu->partner_port_priority = port->partner_oper_port_priority;
|
878 |
|
|
lacpdu->partner_port = port->partner_oper_port_number;
|
879 |
|
|
lacpdu->partner_state = port->partner_oper_port_state;
|
880 |
|
|
|
881 |
|
|
/* lacpdu->reserved_3_2 initialized
|
882 |
|
|
* lacpdu->tlv_type_collector_info initialized
|
883 |
|
|
* lacpdu->collector_information_length initialized
|
884 |
|
|
* collector_max_delay initialized
|
885 |
|
|
* reserved_12[12] initialized
|
886 |
|
|
* tlv_type_terminator initialized
|
887 |
|
|
* terminator_length initialized
|
888 |
|
|
* reserved_50[50] initialized
|
889 |
|
|
*/
|
890 |
|
|
|
891 |
|
|
/* Convert all non u8 parameters to Big Endian for transmit */
|
892 |
|
|
__ntohs_lacpdu(lacpdu);
|
893 |
|
|
}
|
894 |
|
|
|
895 |
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
896 |
|
|
// ================= main 802.3ad protocol code ======================================
|
897 |
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
898 |
|
|
|
899 |
|
|
/**
|
900 |
|
|
* ad_lacpdu_send - send out a lacpdu packet on a given port
|
901 |
|
|
* @port: the port we're looking at
|
902 |
|
|
*
|
903 |
|
|
* Returns: 0 on success
|
904 |
|
|
* < 0 on error
|
905 |
|
|
*/
|
906 |
|
|
static int ad_lacpdu_send(struct port *port)
|
907 |
|
|
{
|
908 |
|
|
struct slave *slave = port->slave;
|
909 |
|
|
struct sk_buff *skb;
|
910 |
|
|
struct lacpdu_header *lacpdu_header;
|
911 |
|
|
int length = sizeof(struct lacpdu_header);
|
912 |
|
|
struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR;
|
913 |
|
|
|
914 |
|
|
skb = dev_alloc_skb(length);
|
915 |
|
|
if (!skb) {
|
916 |
|
|
return -ENOMEM;
|
917 |
|
|
}
|
918 |
|
|
|
919 |
|
|
skb->dev = slave->dev;
|
920 |
|
|
skb->mac.raw = skb->data;
|
921 |
|
|
skb->nh.raw = skb->data + ETH_HLEN;
|
922 |
|
|
skb->protocol = PKT_TYPE_LACPDU;
|
923 |
|
|
skb->priority = TC_PRIO_CONTROL;
|
924 |
|
|
|
925 |
|
|
lacpdu_header = (struct lacpdu_header *)skb_put(skb, length);
|
926 |
|
|
|
927 |
|
|
lacpdu_header->ad_header.destination_address = lacpdu_multicast_address;
|
928 |
|
|
/* Note: source addres is set to be the member's PERMANENT address, because we use it
|
929 |
|
|
to identify loopback lacpdus in receive. */
|
930 |
|
|
lacpdu_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr));
|
931 |
|
|
lacpdu_header->ad_header.length_type = PKT_TYPE_LACPDU;
|
932 |
|
|
|
933 |
|
|
lacpdu_header->lacpdu = port->lacpdu; // struct copy
|
934 |
|
|
|
935 |
|
|
dev_queue_xmit(skb);
|
936 |
|
|
|
937 |
|
|
return 0;
|
938 |
|
|
}
|
939 |
|
|
|
940 |
|
|
/**
|
941 |
|
|
* ad_marker_send - send marker information/response on a given port
|
942 |
|
|
* @port: the port we're looking at
|
943 |
|
|
* @marker: marker data to send
|
944 |
|
|
*
|
945 |
|
|
* Returns: 0 on success
|
946 |
|
|
* < 0 on error
|
947 |
|
|
*/
|
948 |
|
|
static int ad_marker_send(struct port *port, struct marker *marker)
|
949 |
|
|
{
|
950 |
|
|
struct slave *slave = port->slave;
|
951 |
|
|
struct sk_buff *skb;
|
952 |
|
|
struct marker_header *marker_header;
|
953 |
|
|
int length = sizeof(struct marker_header);
|
954 |
|
|
struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR;
|
955 |
|
|
|
956 |
|
|
skb = dev_alloc_skb(length + 16);
|
957 |
|
|
if (!skb) {
|
958 |
|
|
return -ENOMEM;
|
959 |
|
|
}
|
960 |
|
|
|
961 |
|
|
skb_reserve(skb, 16);
|
962 |
|
|
|
963 |
|
|
skb->dev = slave->dev;
|
964 |
|
|
skb->mac.raw = skb->data;
|
965 |
|
|
skb->nh.raw = skb->data + ETH_HLEN;
|
966 |
|
|
skb->protocol = PKT_TYPE_LACPDU;
|
967 |
|
|
|
968 |
|
|
marker_header = (struct marker_header *)skb_put(skb, length);
|
969 |
|
|
|
970 |
|
|
marker_header->ad_header.destination_address = lacpdu_multicast_address;
|
971 |
|
|
/* Note: source addres is set to be the member's PERMANENT address, because we use it
|
972 |
|
|
to identify loopback MARKERs in receive. */
|
973 |
|
|
marker_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr));
|
974 |
|
|
marker_header->ad_header.length_type = PKT_TYPE_LACPDU;
|
975 |
|
|
|
976 |
|
|
marker_header->marker = *marker; // struct copy
|
977 |
|
|
|
978 |
|
|
dev_queue_xmit(skb);
|
979 |
|
|
|
980 |
|
|
return 0;
|
981 |
|
|
}
|
982 |
|
|
|
983 |
|
|
/**
|
984 |
|
|
* ad_mux_machine - handle a port's mux state machine
|
985 |
|
|
* @port: the port we're looking at
|
986 |
|
|
*
|
987 |
|
|
*/
|
988 |
|
|
static void ad_mux_machine(struct port *port)
|
989 |
|
|
{
|
990 |
|
|
mux_states_t last_state;
|
991 |
|
|
|
992 |
|
|
// keep current State Machine state to compare later if it was changed
|
993 |
|
|
last_state = port->sm_mux_state;
|
994 |
|
|
|
995 |
|
|
if (port->sm_vars & AD_PORT_BEGIN) {
|
996 |
|
|
port->sm_mux_state = AD_MUX_DETACHED; // next state
|
997 |
|
|
} else {
|
998 |
|
|
switch (port->sm_mux_state) {
|
999 |
|
|
case AD_MUX_DETACHED:
|
1000 |
|
|
if ((port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { // if SELECTED or STANDBY
|
1001 |
|
|
port->sm_mux_state = AD_MUX_WAITING; // next state
|
1002 |
|
|
}
|
1003 |
|
|
break;
|
1004 |
|
|
case AD_MUX_WAITING:
|
1005 |
|
|
// if SELECTED == FALSE return to DETACH state
|
1006 |
|
|
if (!(port->sm_vars & AD_PORT_SELECTED)) { // if UNSELECTED
|
1007 |
|
|
port->sm_vars &= ~AD_PORT_READY_N;
|
1008 |
|
|
// in order to withhold the Selection Logic to check all ports READY_N value
|
1009 |
|
|
// every callback cycle to update ready variable, we check READY_N and update READY here
|
1010 |
|
|
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
|
1011 |
|
|
port->sm_mux_state = AD_MUX_DETACHED; // next state
|
1012 |
|
|
break;
|
1013 |
|
|
}
|
1014 |
|
|
|
1015 |
|
|
// check if the wait_while_timer expired
|
1016 |
|
|
if (port->sm_mux_timer_counter && !(--port->sm_mux_timer_counter)) {
|
1017 |
|
|
port->sm_vars |= AD_PORT_READY_N;
|
1018 |
|
|
}
|
1019 |
|
|
|
1020 |
|
|
// in order to withhold the selection logic to check all ports READY_N value
|
1021 |
|
|
// every callback cycle to update ready variable, we check READY_N and update READY here
|
1022 |
|
|
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
|
1023 |
|
|
|
1024 |
|
|
// if the wait_while_timer expired, and the port is in READY state, move to ATTACHED state
|
1025 |
|
|
if ((port->sm_vars & AD_PORT_READY) && !port->sm_mux_timer_counter) {
|
1026 |
|
|
port->sm_mux_state = AD_MUX_ATTACHED; // next state
|
1027 |
|
|
}
|
1028 |
|
|
break;
|
1029 |
|
|
case AD_MUX_ATTACHED:
|
1030 |
|
|
// check also if agg_select_timer expired(so the edable port will take place only after this timer)
|
1031 |
|
|
if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) {
|
1032 |
|
|
port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;// next state
|
1033 |
|
|
} else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { // if UNSELECTED or STANDBY
|
1034 |
|
|
port->sm_vars &= ~AD_PORT_READY_N;
|
1035 |
|
|
// in order to withhold the selection logic to check all ports READY_N value
|
1036 |
|
|
// every callback cycle to update ready variable, we check READY_N and update READY here
|
1037 |
|
|
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
|
1038 |
|
|
port->sm_mux_state = AD_MUX_DETACHED;// next state
|
1039 |
|
|
}
|
1040 |
|
|
break;
|
1041 |
|
|
case AD_MUX_COLLECTING_DISTRIBUTING:
|
1042 |
|
|
if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) ||
|
1043 |
|
|
!(port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION)
|
1044 |
|
|
) {
|
1045 |
|
|
port->sm_mux_state = AD_MUX_ATTACHED;// next state
|
1046 |
|
|
|
1047 |
|
|
} else {
|
1048 |
|
|
// if port state hasn't changed make
|
1049 |
|
|
// sure that a collecting distributing
|
1050 |
|
|
// port in an active aggregator is enabled
|
1051 |
|
|
if (port->aggregator &&
|
1052 |
|
|
port->aggregator->is_active &&
|
1053 |
|
|
!__port_is_enabled(port)) {
|
1054 |
|
|
|
1055 |
|
|
__enable_port(port);
|
1056 |
|
|
}
|
1057 |
|
|
}
|
1058 |
|
|
break;
|
1059 |
|
|
default: //to silence the compiler
|
1060 |
|
|
break;
|
1061 |
|
|
}
|
1062 |
|
|
}
|
1063 |
|
|
|
1064 |
|
|
// check if the state machine was changed
|
1065 |
|
|
if (port->sm_mux_state != last_state) {
|
1066 |
|
|
dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state);
|
1067 |
|
|
switch (port->sm_mux_state) {
|
1068 |
|
|
case AD_MUX_DETACHED:
|
1069 |
|
|
__detach_bond_from_agg(port);
|
1070 |
|
|
port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
|
1071 |
|
|
ad_disable_collecting_distributing(port);
|
1072 |
|
|
port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
|
1073 |
|
|
port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
|
1074 |
|
|
port->ntt = 1;
|
1075 |
|
|
break;
|
1076 |
|
|
case AD_MUX_WAITING:
|
1077 |
|
|
port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
|
1078 |
|
|
break;
|
1079 |
|
|
case AD_MUX_ATTACHED:
|
1080 |
|
|
__attach_bond_to_agg(port);
|
1081 |
|
|
port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION;
|
1082 |
|
|
port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
|
1083 |
|
|
port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
|
1084 |
|
|
ad_disable_collecting_distributing(port);
|
1085 |
|
|
port->ntt = 1;
|
1086 |
|
|
break;
|
1087 |
|
|
case AD_MUX_COLLECTING_DISTRIBUTING:
|
1088 |
|
|
port->actor_oper_port_state |= AD_STATE_COLLECTING;
|
1089 |
|
|
port->actor_oper_port_state |= AD_STATE_DISTRIBUTING;
|
1090 |
|
|
ad_enable_collecting_distributing(port);
|
1091 |
|
|
port->ntt = 1;
|
1092 |
|
|
break;
|
1093 |
|
|
default: //to silence the compiler
|
1094 |
|
|
break;
|
1095 |
|
|
}
|
1096 |
|
|
}
|
1097 |
|
|
}
|
1098 |
|
|
|
1099 |
|
|
/**
|
1100 |
|
|
* ad_rx_machine - handle a port's rx State Machine
|
1101 |
|
|
* @lacpdu: the lacpdu we've received
|
1102 |
|
|
* @port: the port we're looking at
|
1103 |
|
|
*
|
1104 |
|
|
* If lacpdu arrived, stop previous timer (if exists) and set the next state as
|
1105 |
|
|
* CURRENT. If timer expired set the state machine in the proper state.
|
1106 |
|
|
* In other cases, this function checks if we need to switch to other state.
|
1107 |
|
|
*/
|
1108 |
|
|
static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
|
1109 |
|
|
{
|
1110 |
|
|
rx_states_t last_state;
|
1111 |
|
|
|
1112 |
|
|
// Lock to prevent 2 instances of this function to run simultaneously(rx interrupt and periodic machine callback)
|
1113 |
|
|
__get_rx_machine_lock(port);
|
1114 |
|
|
|
1115 |
|
|
// keep current State Machine state to compare later if it was changed
|
1116 |
|
|
last_state = port->sm_rx_state;
|
1117 |
|
|
|
1118 |
|
|
// check if state machine should change state
|
1119 |
|
|
// first, check if port was reinitialized
|
1120 |
|
|
if (port->sm_vars & AD_PORT_BEGIN) {
|
1121 |
|
|
port->sm_rx_state = AD_RX_INITIALIZE; // next state
|
1122 |
|
|
}
|
1123 |
|
|
// check if port is not enabled
|
1124 |
|
|
else if (!(port->sm_vars & AD_PORT_BEGIN) && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED)) {
|
1125 |
|
|
port->sm_rx_state = AD_RX_PORT_DISABLED; // next state
|
1126 |
|
|
}
|
1127 |
|
|
// check if new lacpdu arrived
|
1128 |
|
|
else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) || (port->sm_rx_state == AD_RX_DEFAULTED) || (port->sm_rx_state == AD_RX_CURRENT))) {
|
1129 |
|
|
port->sm_rx_timer_counter = 0; // zero timer
|
1130 |
|
|
port->sm_rx_state = AD_RX_CURRENT;
|
1131 |
|
|
} else {
|
1132 |
|
|
// if timer is on, and if it is expired
|
1133 |
|
|
if (port->sm_rx_timer_counter && !(--port->sm_rx_timer_counter)) {
|
1134 |
|
|
switch (port->sm_rx_state) {
|
1135 |
|
|
case AD_RX_EXPIRED:
|
1136 |
|
|
port->sm_rx_state = AD_RX_DEFAULTED; // next state
|
1137 |
|
|
break;
|
1138 |
|
|
case AD_RX_CURRENT:
|
1139 |
|
|
port->sm_rx_state = AD_RX_EXPIRED; // next state
|
1140 |
|
|
break;
|
1141 |
|
|
default: //to silence the compiler
|
1142 |
|
|
break;
|
1143 |
|
|
}
|
1144 |
|
|
} else {
|
1145 |
|
|
// if no lacpdu arrived and no timer is on
|
1146 |
|
|
switch (port->sm_rx_state) {
|
1147 |
|
|
case AD_RX_PORT_DISABLED:
|
1148 |
|
|
if (port->sm_vars & AD_PORT_MOVED) {
|
1149 |
|
|
port->sm_rx_state = AD_RX_INITIALIZE; // next state
|
1150 |
|
|
} else if (port->is_enabled && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
|
1151 |
|
|
port->sm_rx_state = AD_RX_EXPIRED; // next state
|
1152 |
|
|
} else if (port->is_enabled && ((port->sm_vars & AD_PORT_LACP_ENABLED) == 0)) {
|
1153 |
|
|
port->sm_rx_state = AD_RX_LACP_DISABLED; // next state
|
1154 |
|
|
}
|
1155 |
|
|
break;
|
1156 |
|
|
default: //to silence the compiler
|
1157 |
|
|
break;
|
1158 |
|
|
|
1159 |
|
|
}
|
1160 |
|
|
}
|
1161 |
|
|
}
|
1162 |
|
|
|
1163 |
|
|
// check if the State machine was changed or new lacpdu arrived
|
1164 |
|
|
if ((port->sm_rx_state != last_state) || (lacpdu)) {
|
1165 |
|
|
dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state);
|
1166 |
|
|
switch (port->sm_rx_state) {
|
1167 |
|
|
case AD_RX_INITIALIZE:
|
1168 |
|
|
if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) {
|
1169 |
|
|
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
|
1170 |
|
|
} else {
|
1171 |
|
|
port->sm_vars |= AD_PORT_LACP_ENABLED;
|
1172 |
|
|
}
|
1173 |
|
|
port->sm_vars &= ~AD_PORT_SELECTED;
|
1174 |
|
|
__record_default(port);
|
1175 |
|
|
port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
|
1176 |
|
|
port->sm_vars &= ~AD_PORT_MOVED;
|
1177 |
|
|
port->sm_rx_state = AD_RX_PORT_DISABLED; // next state
|
1178 |
|
|
|
1179 |
|
|
/*- Fall Through -*/
|
1180 |
|
|
|
1181 |
|
|
case AD_RX_PORT_DISABLED:
|
1182 |
|
|
port->sm_vars &= ~AD_PORT_MATCHED;
|
1183 |
|
|
break;
|
1184 |
|
|
case AD_RX_LACP_DISABLED:
|
1185 |
|
|
port->sm_vars &= ~AD_PORT_SELECTED;
|
1186 |
|
|
__record_default(port);
|
1187 |
|
|
port->partner_oper_port_state &= ~AD_STATE_AGGREGATION;
|
1188 |
|
|
port->sm_vars |= AD_PORT_MATCHED;
|
1189 |
|
|
port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
|
1190 |
|
|
break;
|
1191 |
|
|
case AD_RX_EXPIRED:
|
1192 |
|
|
//Reset of the Synchronization flag. (Standard 43.4.12)
|
1193 |
|
|
//This reset cause to disable this port in the COLLECTING_DISTRIBUTING state of the
|
1194 |
|
|
//mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port.
|
1195 |
|
|
port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
|
1196 |
|
|
port->sm_vars &= ~AD_PORT_MATCHED;
|
1197 |
|
|
port->partner_oper_port_state |= AD_SHORT_TIMEOUT;
|
1198 |
|
|
port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
|
1199 |
|
|
port->actor_oper_port_state |= AD_STATE_EXPIRED;
|
1200 |
|
|
break;
|
1201 |
|
|
case AD_RX_DEFAULTED:
|
1202 |
|
|
__update_default_selected(port);
|
1203 |
|
|
__record_default(port);
|
1204 |
|
|
port->sm_vars |= AD_PORT_MATCHED;
|
1205 |
|
|
port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
|
1206 |
|
|
break;
|
1207 |
|
|
case AD_RX_CURRENT:
|
1208 |
|
|
// detect loopback situation
|
1209 |
|
|
if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) {
|
1210 |
|
|
// INFO_RECEIVED_LOOPBACK_FRAMES
|
1211 |
|
|
printk(KERN_ERR DRV_NAME ": An illegal loopback occurred on adapter (%s)\n",
|
1212 |
|
|
port->slave->dev->name);
|
1213 |
|
|
printk(KERN_ERR "Check the configuration to verify that all Adapters "
|
1214 |
|
|
"are connected to 802.3ad compliant switch ports\n");
|
1215 |
|
|
__release_rx_machine_lock(port);
|
1216 |
|
|
return;
|
1217 |
|
|
}
|
1218 |
|
|
__update_selected(lacpdu, port);
|
1219 |
|
|
__update_ntt(lacpdu, port);
|
1220 |
|
|
__record_pdu(lacpdu, port);
|
1221 |
|
|
__choose_matched(lacpdu, port);
|
1222 |
|
|
port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT));
|
1223 |
|
|
port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
|
1224 |
|
|
// verify that if the aggregator is enabled, the port is enabled too.
|
1225 |
|
|
//(because if the link goes down for a short time, the 802.3ad will not
|
1226 |
|
|
// catch it, and the port will continue to be disabled)
|
1227 |
|
|
if (port->aggregator && port->aggregator->is_active && !__port_is_enabled(port)) {
|
1228 |
|
|
__enable_port(port);
|
1229 |
|
|
}
|
1230 |
|
|
break;
|
1231 |
|
|
default: //to silence the compiler
|
1232 |
|
|
break;
|
1233 |
|
|
}
|
1234 |
|
|
}
|
1235 |
|
|
__release_rx_machine_lock(port);
|
1236 |
|
|
}
|
1237 |
|
|
|
1238 |
|
|
/**
|
1239 |
|
|
* ad_tx_machine - handle a port's tx state machine
|
1240 |
|
|
* @port: the port we're looking at
|
1241 |
|
|
*
|
1242 |
|
|
*/
|
1243 |
|
|
static void ad_tx_machine(struct port *port)
|
1244 |
|
|
{
|
1245 |
|
|
// check if tx timer expired, to verify that we do not send more than 3 packets per second
|
1246 |
|
|
if (port->sm_tx_timer_counter && !(--port->sm_tx_timer_counter)) {
|
1247 |
|
|
// check if there is something to send
|
1248 |
|
|
if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
|
1249 |
|
|
__update_lacpdu_from_port(port);
|
1250 |
|
|
// send the lacpdu
|
1251 |
|
|
if (ad_lacpdu_send(port) >= 0) {
|
1252 |
|
|
dprintk("Sent LACPDU on port %d\n", port->actor_port_number);
|
1253 |
|
|
// mark ntt as false, so it will not be sent again until demanded
|
1254 |
|
|
port->ntt = 0;
|
1255 |
|
|
}
|
1256 |
|
|
}
|
1257 |
|
|
// restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND
|
1258 |
|
|
port->sm_tx_timer_counter=ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
|
1259 |
|
|
}
|
1260 |
|
|
}
|
1261 |
|
|
|
1262 |
|
|
/**
|
1263 |
|
|
* ad_periodic_machine - handle a port's periodic state machine
|
1264 |
|
|
* @port: the port we're looking at
|
1265 |
|
|
*
|
1266 |
|
|
* Turn ntt flag on priodically to perform periodic transmission of lacpdu's.
|
1267 |
|
|
*/
|
1268 |
|
|
static void ad_periodic_machine(struct port *port)
|
1269 |
|
|
{
|
1270 |
|
|
periodic_states_t last_state;
|
1271 |
|
|
|
1272 |
|
|
// keep current state machine state to compare later if it was changed
|
1273 |
|
|
last_state = port->sm_periodic_state;
|
1274 |
|
|
|
1275 |
|
|
// check if port was reinitialized
|
1276 |
|
|
if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) ||
|
1277 |
|
|
(!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper_port_state & AD_STATE_LACP_ACTIVITY))
|
1278 |
|
|
) {
|
1279 |
|
|
port->sm_periodic_state = AD_NO_PERIODIC; // next state
|
1280 |
|
|
}
|
1281 |
|
|
// check if state machine should change state
|
1282 |
|
|
else if (port->sm_periodic_timer_counter) {
|
1283 |
|
|
// check if periodic state machine expired
|
1284 |
|
|
if (!(--port->sm_periodic_timer_counter)) {
|
1285 |
|
|
// if expired then do tx
|
1286 |
|
|
port->sm_periodic_state = AD_PERIODIC_TX; // next state
|
1287 |
|
|
} else {
|
1288 |
|
|
// If not expired, check if there is some new timeout parameter from the partner state
|
1289 |
|
|
switch (port->sm_periodic_state) {
|
1290 |
|
|
case AD_FAST_PERIODIC:
|
1291 |
|
|
if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
|
1292 |
|
|
port->sm_periodic_state = AD_SLOW_PERIODIC; // next state
|
1293 |
|
|
}
|
1294 |
|
|
break;
|
1295 |
|
|
case AD_SLOW_PERIODIC:
|
1296 |
|
|
if ((port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
|
1297 |
|
|
// stop current timer
|
1298 |
|
|
port->sm_periodic_timer_counter = 0;
|
1299 |
|
|
port->sm_periodic_state = AD_PERIODIC_TX; // next state
|
1300 |
|
|
}
|
1301 |
|
|
break;
|
1302 |
|
|
default: //to silence the compiler
|
1303 |
|
|
break;
|
1304 |
|
|
}
|
1305 |
|
|
}
|
1306 |
|
|
} else {
|
1307 |
|
|
switch (port->sm_periodic_state) {
|
1308 |
|
|
case AD_NO_PERIODIC:
|
1309 |
|
|
port->sm_periodic_state = AD_FAST_PERIODIC; // next state
|
1310 |
|
|
break;
|
1311 |
|
|
case AD_PERIODIC_TX:
|
1312 |
|
|
if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
|
1313 |
|
|
port->sm_periodic_state = AD_SLOW_PERIODIC; // next state
|
1314 |
|
|
} else {
|
1315 |
|
|
port->sm_periodic_state = AD_FAST_PERIODIC; // next state
|
1316 |
|
|
}
|
1317 |
|
|
break;
|
1318 |
|
|
default: //to silence the compiler
|
1319 |
|
|
break;
|
1320 |
|
|
}
|
1321 |
|
|
}
|
1322 |
|
|
|
1323 |
|
|
// check if the state machine was changed
|
1324 |
|
|
if (port->sm_periodic_state != last_state) {
|
1325 |
|
|
dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state);
|
1326 |
|
|
switch (port->sm_periodic_state) {
|
1327 |
|
|
case AD_NO_PERIODIC:
|
1328 |
|
|
port->sm_periodic_timer_counter = 0; // zero timer
|
1329 |
|
|
break;
|
1330 |
|
|
case AD_FAST_PERIODIC:
|
1331 |
|
|
port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_FAST_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle
|
1332 |
|
|
break;
|
1333 |
|
|
case AD_SLOW_PERIODIC:
|
1334 |
|
|
port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle
|
1335 |
|
|
break;
|
1336 |
|
|
case AD_PERIODIC_TX:
|
1337 |
|
|
port->ntt = 1;
|
1338 |
|
|
break;
|
1339 |
|
|
default: //to silence the compiler
|
1340 |
|
|
break;
|
1341 |
|
|
}
|
1342 |
|
|
}
|
1343 |
|
|
}
|
1344 |
|
|
|
1345 |
|
|
/**
|
1346 |
|
|
* ad_port_selection_logic - select aggregation groups
|
1347 |
|
|
* @port: the port we're looking at
|
1348 |
|
|
*
|
1349 |
|
|
* Select aggregation groups, and assign each port for it's aggregetor. The
|
1350 |
|
|
* selection logic is called in the inititalization (after all the handshkes),
|
1351 |
|
|
* and after every lacpdu receive (if selected is off).
|
1352 |
|
|
*/
|
1353 |
|
|
static void ad_port_selection_logic(struct port *port)
|
1354 |
|
|
{
|
1355 |
|
|
struct aggregator *aggregator, *free_aggregator = NULL, *temp_aggregator;
|
1356 |
|
|
struct port *last_port = NULL, *curr_port;
|
1357 |
|
|
int found = 0;
|
1358 |
|
|
|
1359 |
|
|
// if the port is already Selected, do nothing
|
1360 |
|
|
if (port->sm_vars & AD_PORT_SELECTED) {
|
1361 |
|
|
return;
|
1362 |
|
|
}
|
1363 |
|
|
|
1364 |
|
|
// if the port is connected to other aggregator, detach it
|
1365 |
|
|
if (port->aggregator) {
|
1366 |
|
|
// detach the port from its former aggregator
|
1367 |
|
|
temp_aggregator=port->aggregator;
|
1368 |
|
|
for (curr_port=temp_aggregator->lag_ports; curr_port; last_port=curr_port, curr_port=curr_port->next_port_in_aggregator) {
|
1369 |
|
|
if (curr_port == port) {
|
1370 |
|
|
temp_aggregator->num_of_ports--;
|
1371 |
|
|
if (!last_port) {// if it is the first port attached to the aggregator
|
1372 |
|
|
temp_aggregator->lag_ports=port->next_port_in_aggregator;
|
1373 |
|
|
} else {// not the first port attached to the aggregator
|
1374 |
|
|
last_port->next_port_in_aggregator=port->next_port_in_aggregator;
|
1375 |
|
|
}
|
1376 |
|
|
|
1377 |
|
|
// clear the port's relations to this aggregator
|
1378 |
|
|
port->aggregator = NULL;
|
1379 |
|
|
port->next_port_in_aggregator=NULL;
|
1380 |
|
|
port->actor_port_aggregator_identifier=0;
|
1381 |
|
|
|
1382 |
|
|
dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier);
|
1383 |
|
|
// if the aggregator is empty, clear its parameters, and set it ready to be attached
|
1384 |
|
|
if (!temp_aggregator->lag_ports) {
|
1385 |
|
|
ad_clear_agg(temp_aggregator);
|
1386 |
|
|
}
|
1387 |
|
|
break;
|
1388 |
|
|
}
|
1389 |
|
|
}
|
1390 |
|
|
if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list
|
1391 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: Port %d (on %s) was "
|
1392 |
|
|
"related to aggregator %d but was not on its port list\n",
|
1393 |
|
|
port->actor_port_number, port->slave->dev->name,
|
1394 |
|
|
port->aggregator->aggregator_identifier);
|
1395 |
|
|
}
|
1396 |
|
|
}
|
1397 |
|
|
// search on all aggregators for a suitable aggregator for this port
|
1398 |
|
|
for (aggregator = __get_first_agg(port); aggregator;
|
1399 |
|
|
aggregator = __get_next_agg(aggregator)) {
|
1400 |
|
|
|
1401 |
|
|
// keep a free aggregator for later use(if needed)
|
1402 |
|
|
if (!aggregator->lag_ports) {
|
1403 |
|
|
if (!free_aggregator) {
|
1404 |
|
|
free_aggregator=aggregator;
|
1405 |
|
|
}
|
1406 |
|
|
continue;
|
1407 |
|
|
}
|
1408 |
|
|
// check if current aggregator suits us
|
1409 |
|
|
if (((aggregator->actor_oper_aggregator_key == port->actor_oper_port_key) && // if all parameters match AND
|
1410 |
|
|
!MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper_system)) &&
|
1411 |
|
|
(aggregator->partner_system_priority == port->partner_oper_system_priority) &&
|
1412 |
|
|
(aggregator->partner_oper_aggregator_key == port->partner_oper_key)
|
1413 |
|
|
) &&
|
1414 |
|
|
((MAC_ADDRESS_COMPARE(&(port->partner_oper_system), &(null_mac_addr)) && // partner answers
|
1415 |
|
|
!aggregator->is_individual) // but is not individual OR
|
1416 |
|
|
)
|
1417 |
|
|
) {
|
1418 |
|
|
// attach to the founded aggregator
|
1419 |
|
|
port->aggregator = aggregator;
|
1420 |
|
|
port->actor_port_aggregator_identifier=port->aggregator->aggregator_identifier;
|
1421 |
|
|
port->next_port_in_aggregator=aggregator->lag_ports;
|
1422 |
|
|
port->aggregator->num_of_ports++;
|
1423 |
|
|
aggregator->lag_ports=port;
|
1424 |
|
|
dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
|
1425 |
|
|
|
1426 |
|
|
// mark this port as selected
|
1427 |
|
|
port->sm_vars |= AD_PORT_SELECTED;
|
1428 |
|
|
found = 1;
|
1429 |
|
|
break;
|
1430 |
|
|
}
|
1431 |
|
|
}
|
1432 |
|
|
|
1433 |
|
|
// the port couldn't find an aggregator - attach it to a new aggregator
|
1434 |
|
|
if (!found) {
|
1435 |
|
|
if (free_aggregator) {
|
1436 |
|
|
// assign port a new aggregator
|
1437 |
|
|
port->aggregator = free_aggregator;
|
1438 |
|
|
port->actor_port_aggregator_identifier=port->aggregator->aggregator_identifier;
|
1439 |
|
|
|
1440 |
|
|
// update the new aggregator's parameters
|
1441 |
|
|
// if port was responsed from the end-user
|
1442 |
|
|
if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) {// if port is full duplex
|
1443 |
|
|
port->aggregator->is_individual = 0;
|
1444 |
|
|
} else {
|
1445 |
|
|
port->aggregator->is_individual = 1;
|
1446 |
|
|
}
|
1447 |
|
|
|
1448 |
|
|
port->aggregator->actor_admin_aggregator_key = port->actor_admin_port_key;
|
1449 |
|
|
port->aggregator->actor_oper_aggregator_key = port->actor_oper_port_key;
|
1450 |
|
|
port->aggregator->partner_system=port->partner_oper_system;
|
1451 |
|
|
port->aggregator->partner_system_priority = port->partner_oper_system_priority;
|
1452 |
|
|
port->aggregator->partner_oper_aggregator_key = port->partner_oper_key;
|
1453 |
|
|
port->aggregator->receive_state = 1;
|
1454 |
|
|
port->aggregator->transmit_state = 1;
|
1455 |
|
|
port->aggregator->lag_ports = port;
|
1456 |
|
|
port->aggregator->num_of_ports++;
|
1457 |
|
|
|
1458 |
|
|
// mark this port as selected
|
1459 |
|
|
port->sm_vars |= AD_PORT_SELECTED;
|
1460 |
|
|
|
1461 |
|
|
dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
|
1462 |
|
|
} else {
|
1463 |
|
|
printk(KERN_ERR DRV_NAME ": Port %d (on %s) did not find a suitable aggregator\n",
|
1464 |
|
|
port->actor_port_number, port->slave->dev->name);
|
1465 |
|
|
}
|
1466 |
|
|
}
|
1467 |
|
|
// if all aggregator's ports are READY_N == TRUE, set ready=TRUE in all aggregator's ports
|
1468 |
|
|
// else set ready=FALSE in all aggregator's ports
|
1469 |
|
|
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
|
1470 |
|
|
|
1471 |
|
|
if (!__check_agg_selection_timer(port) && (aggregator = __get_first_agg(port))) {
|
1472 |
|
|
ad_agg_selection_logic(aggregator);
|
1473 |
|
|
}
|
1474 |
|
|
}
|
1475 |
|
|
|
1476 |
|
|
/**
|
1477 |
|
|
* ad_agg_selection_logic - select an aggregation group for a team
|
1478 |
|
|
* @aggregator: the aggregator we're looking at
|
1479 |
|
|
*
|
1480 |
|
|
* It is assumed that only one aggregator may be selected for a team.
|
1481 |
|
|
* The logic of this function is to select (at first time) the aggregator with
|
1482 |
|
|
* the most ports attached to it, and to reselect the active aggregator only if
|
1483 |
|
|
* the previous aggregator has no more ports related to it.
|
1484 |
|
|
*
|
1485 |
|
|
* FIXME: this function MUST be called with the first agg in the bond, or
|
1486 |
|
|
* __get_active_agg() won't work correctly. This function should be better
|
1487 |
|
|
* called with the bond itself, and retrieve the first agg from it.
|
1488 |
|
|
*/
|
1489 |
|
|
static void ad_agg_selection_logic(struct aggregator *aggregator)
|
1490 |
|
|
{
|
1491 |
|
|
struct aggregator *best_aggregator = NULL, *active_aggregator = NULL;
|
1492 |
|
|
struct aggregator *last_active_aggregator = NULL, *origin_aggregator;
|
1493 |
|
|
struct port *port;
|
1494 |
|
|
u16 num_of_aggs=0;
|
1495 |
|
|
|
1496 |
|
|
origin_aggregator = aggregator;
|
1497 |
|
|
|
1498 |
|
|
//get current active aggregator
|
1499 |
|
|
last_active_aggregator = __get_active_agg(aggregator);
|
1500 |
|
|
|
1501 |
|
|
// search for the aggregator with the most ports attached to it.
|
1502 |
|
|
do {
|
1503 |
|
|
// count how many candidate lag's we have
|
1504 |
|
|
if (aggregator->lag_ports) {
|
1505 |
|
|
num_of_aggs++;
|
1506 |
|
|
}
|
1507 |
|
|
if (aggregator->is_active && !aggregator->is_individual && // if current aggregator is the active aggregator
|
1508 |
|
|
MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr))) { // and partner answers to 802.3ad PDUs
|
1509 |
|
|
if (aggregator->num_of_ports) { // if any ports attached to the current aggregator
|
1510 |
|
|
best_aggregator=NULL; // disregard the best aggregator that was chosen by now
|
1511 |
|
|
break; // stop the selection of other aggregator if there are any ports attached to this active aggregator
|
1512 |
|
|
} else { // no ports attached to this active aggregator
|
1513 |
|
|
aggregator->is_active = 0; // mark this aggregator as not active anymore
|
1514 |
|
|
}
|
1515 |
|
|
}
|
1516 |
|
|
if (aggregator->num_of_ports) { // if any ports attached
|
1517 |
|
|
if (best_aggregator) { // if there is a candidte aggregator
|
1518 |
|
|
//The reasons for choosing new best aggregator:
|
1519 |
|
|
// 1. if current agg is NOT individual and the best agg chosen so far is individual OR
|
1520 |
|
|
// current and best aggs are both individual or both not individual, AND
|
1521 |
|
|
// 2a. current agg partner reply but best agg partner do not reply OR
|
1522 |
|
|
// 2b. current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply AND
|
1523 |
|
|
// current has more ports/bandwidth, or same amount of ports but current has faster ports, THEN
|
1524 |
|
|
// current agg become best agg so far
|
1525 |
|
|
|
1526 |
|
|
//if current agg is NOT individual and the best agg chosen so far is individual change best_aggregator
|
1527 |
|
|
if (!aggregator->is_individual && best_aggregator->is_individual) {
|
1528 |
|
|
best_aggregator=aggregator;
|
1529 |
|
|
}
|
1530 |
|
|
// current and best aggs are both individual or both not individual
|
1531 |
|
|
else if ((aggregator->is_individual && best_aggregator->is_individual) ||
|
1532 |
|
|
(!aggregator->is_individual && !best_aggregator->is_individual)) {
|
1533 |
|
|
// current and best aggs are both individual or both not individual AND
|
1534 |
|
|
// current agg partner reply but best agg partner do not reply
|
1535 |
|
|
if ((MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) &&
|
1536 |
|
|
!MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) {
|
1537 |
|
|
best_aggregator=aggregator;
|
1538 |
|
|
}
|
1539 |
|
|
// current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply
|
1540 |
|
|
else if (! (!MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) &&
|
1541 |
|
|
MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) {
|
1542 |
|
|
if ((__get_agg_selection_mode(aggregator->lag_ports) == AD_BANDWIDTH)&&
|
1543 |
|
|
(__get_agg_bandwidth(aggregator) > __get_agg_bandwidth(best_aggregator))) {
|
1544 |
|
|
best_aggregator=aggregator;
|
1545 |
|
|
} else if (__get_agg_selection_mode(aggregator->lag_ports) == AD_COUNT) {
|
1546 |
|
|
if (((aggregator->num_of_ports > best_aggregator->num_of_ports) &&
|
1547 |
|
|
(aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS))||
|
1548 |
|
|
((aggregator->num_of_ports == best_aggregator->num_of_ports) &&
|
1549 |
|
|
((u16)(aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS) >
|
1550 |
|
|
(u16)(best_aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS)))) {
|
1551 |
|
|
best_aggregator=aggregator;
|
1552 |
|
|
}
|
1553 |
|
|
}
|
1554 |
|
|
}
|
1555 |
|
|
}
|
1556 |
|
|
} else {
|
1557 |
|
|
best_aggregator=aggregator;
|
1558 |
|
|
}
|
1559 |
|
|
}
|
1560 |
|
|
aggregator->is_active = 0; // mark all aggregators as not active anymore
|
1561 |
|
|
} while ((aggregator = __get_next_agg(aggregator)));
|
1562 |
|
|
|
1563 |
|
|
// if we have new aggregator selected, don't replace the old aggregator if it has an answering partner,
|
1564 |
|
|
// or if both old aggregator and new aggregator don't have answering partner
|
1565 |
|
|
if (best_aggregator) {
|
1566 |
|
|
if (last_active_aggregator && last_active_aggregator->lag_ports && last_active_aggregator->lag_ports->is_enabled &&
|
1567 |
|
|
(MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) || // partner answers OR
|
1568 |
|
|
(!MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) && // both old and new
|
1569 |
|
|
!MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) // partner do not answer
|
1570 |
|
|
) {
|
1571 |
|
|
// if new aggregator has link, and old aggregator does not, replace old aggregator.(do nothing)
|
1572 |
|
|
// -> don't replace otherwise.
|
1573 |
|
|
if (!(!last_active_aggregator->actor_oper_aggregator_key && best_aggregator->actor_oper_aggregator_key)) {
|
1574 |
|
|
best_aggregator=NULL;
|
1575 |
|
|
last_active_aggregator->is_active = 1; // don't replace good old aggregator
|
1576 |
|
|
|
1577 |
|
|
}
|
1578 |
|
|
}
|
1579 |
|
|
}
|
1580 |
|
|
|
1581 |
|
|
// if there is new best aggregator, activate it
|
1582 |
|
|
if (best_aggregator) {
|
1583 |
|
|
for (aggregator = __get_first_agg(best_aggregator->lag_ports);
|
1584 |
|
|
aggregator;
|
1585 |
|
|
aggregator = __get_next_agg(aggregator)) {
|
1586 |
|
|
|
1587 |
|
|
dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n",
|
1588 |
|
|
aggregator->aggregator_identifier, aggregator->num_of_ports,
|
1589 |
|
|
aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key,
|
1590 |
|
|
aggregator->is_individual, aggregator->is_active);
|
1591 |
|
|
}
|
1592 |
|
|
|
1593 |
|
|
// check if any partner replys
|
1594 |
|
|
if (best_aggregator->is_individual) {
|
1595 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: No 802.3ad response from the link partner "
|
1596 |
|
|
"for any adapters in the bond\n");
|
1597 |
|
|
}
|
1598 |
|
|
|
1599 |
|
|
// check if there are more than one aggregator
|
1600 |
|
|
if (num_of_aggs > 1) {
|
1601 |
|
|
dprintk("Warning: More than one Link Aggregation Group was "
|
1602 |
|
|
"found in the bond. Only one group will function in the bond\n");
|
1603 |
|
|
}
|
1604 |
|
|
|
1605 |
|
|
best_aggregator->is_active = 1;
|
1606 |
|
|
dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier);
|
1607 |
|
|
dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n",
|
1608 |
|
|
best_aggregator->aggregator_identifier, best_aggregator->num_of_ports,
|
1609 |
|
|
best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key,
|
1610 |
|
|
best_aggregator->is_individual, best_aggregator->is_active);
|
1611 |
|
|
|
1612 |
|
|
// disable the ports that were related to the former active_aggregator
|
1613 |
|
|
if (last_active_aggregator) {
|
1614 |
|
|
for (port=last_active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
|
1615 |
|
|
__disable_port(port);
|
1616 |
|
|
}
|
1617 |
|
|
}
|
1618 |
|
|
}
|
1619 |
|
|
|
1620 |
|
|
// if the selected aggregator is of join individuals(partner_system is NULL), enable their ports
|
1621 |
|
|
active_aggregator = __get_active_agg(origin_aggregator);
|
1622 |
|
|
|
1623 |
|
|
if (active_aggregator) {
|
1624 |
|
|
if (!MAC_ADDRESS_COMPARE(&(active_aggregator->partner_system), &(null_mac_addr))) {
|
1625 |
|
|
for (port=active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
|
1626 |
|
|
__enable_port(port);
|
1627 |
|
|
}
|
1628 |
|
|
}
|
1629 |
|
|
}
|
1630 |
|
|
}
|
1631 |
|
|
|
1632 |
|
|
/**
|
1633 |
|
|
* ad_clear_agg - clear a given aggregator's parameters
|
1634 |
|
|
* @aggregator: the aggregator we're looking at
|
1635 |
|
|
*
|
1636 |
|
|
*/
|
1637 |
|
|
static void ad_clear_agg(struct aggregator *aggregator)
|
1638 |
|
|
{
|
1639 |
|
|
if (aggregator) {
|
1640 |
|
|
aggregator->is_individual = 0;
|
1641 |
|
|
aggregator->actor_admin_aggregator_key = 0;
|
1642 |
|
|
aggregator->actor_oper_aggregator_key = 0;
|
1643 |
|
|
aggregator->partner_system = null_mac_addr;
|
1644 |
|
|
aggregator->partner_system_priority = 0;
|
1645 |
|
|
aggregator->partner_oper_aggregator_key = 0;
|
1646 |
|
|
aggregator->receive_state = 0;
|
1647 |
|
|
aggregator->transmit_state = 0;
|
1648 |
|
|
aggregator->lag_ports = NULL;
|
1649 |
|
|
aggregator->is_active = 0;
|
1650 |
|
|
aggregator->num_of_ports = 0;
|
1651 |
|
|
dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier);
|
1652 |
|
|
}
|
1653 |
|
|
}
|
1654 |
|
|
|
1655 |
|
|
/**
|
1656 |
|
|
* ad_initialize_agg - initialize a given aggregator's parameters
|
1657 |
|
|
* @aggregator: the aggregator we're looking at
|
1658 |
|
|
*
|
1659 |
|
|
*/
|
1660 |
|
|
static void ad_initialize_agg(struct aggregator *aggregator)
|
1661 |
|
|
{
|
1662 |
|
|
if (aggregator) {
|
1663 |
|
|
ad_clear_agg(aggregator);
|
1664 |
|
|
|
1665 |
|
|
aggregator->aggregator_mac_address = null_mac_addr;
|
1666 |
|
|
aggregator->aggregator_identifier = 0;
|
1667 |
|
|
aggregator->slave = NULL;
|
1668 |
|
|
}
|
1669 |
|
|
}
|
1670 |
|
|
|
1671 |
|
|
/**
|
1672 |
|
|
* ad_initialize_port - initialize a given port's parameters
|
1673 |
|
|
* @aggregator: the aggregator we're looking at
|
1674 |
|
|
* @lacp_fast: boolean. whether fast periodic should be used
|
1675 |
|
|
*
|
1676 |
|
|
*/
|
1677 |
|
|
static void ad_initialize_port(struct port *port, int lacp_fast)
|
1678 |
|
|
{
|
1679 |
|
|
if (port) {
|
1680 |
|
|
port->actor_port_number = 1;
|
1681 |
|
|
port->actor_port_priority = 0xff;
|
1682 |
|
|
port->actor_system = null_mac_addr;
|
1683 |
|
|
port->actor_system_priority = 0xffff;
|
1684 |
|
|
port->actor_port_aggregator_identifier = 0;
|
1685 |
|
|
port->ntt = 0;
|
1686 |
|
|
port->actor_admin_port_key = 1;
|
1687 |
|
|
port->actor_oper_port_key = 1;
|
1688 |
|
|
port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
|
1689 |
|
|
port->actor_oper_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
|
1690 |
|
|
|
1691 |
|
|
if (lacp_fast) {
|
1692 |
|
|
port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;
|
1693 |
|
|
}
|
1694 |
|
|
|
1695 |
|
|
port->partner_admin_system = null_mac_addr;
|
1696 |
|
|
port->partner_oper_system = null_mac_addr;
|
1697 |
|
|
port->partner_admin_system_priority = 0xffff;
|
1698 |
|
|
port->partner_oper_system_priority = 0xffff;
|
1699 |
|
|
port->partner_admin_key = 1;
|
1700 |
|
|
port->partner_oper_key = 1;
|
1701 |
|
|
port->partner_admin_port_number = 1;
|
1702 |
|
|
port->partner_oper_port_number = 1;
|
1703 |
|
|
port->partner_admin_port_priority = 0xff;
|
1704 |
|
|
port->partner_oper_port_priority = 0xff;
|
1705 |
|
|
port->partner_admin_port_state = 1;
|
1706 |
|
|
port->partner_oper_port_state = 1;
|
1707 |
|
|
port->is_enabled = 1;
|
1708 |
|
|
// ****** private parameters ******
|
1709 |
|
|
port->sm_vars = 0x3;
|
1710 |
|
|
port->sm_rx_state = 0;
|
1711 |
|
|
port->sm_rx_timer_counter = 0;
|
1712 |
|
|
port->sm_periodic_state = 0;
|
1713 |
|
|
port->sm_periodic_timer_counter = 0;
|
1714 |
|
|
port->sm_mux_state = 0;
|
1715 |
|
|
port->sm_mux_timer_counter = 0;
|
1716 |
|
|
port->sm_tx_state = 0;
|
1717 |
|
|
port->sm_tx_timer_counter = 0;
|
1718 |
|
|
port->slave = NULL;
|
1719 |
|
|
port->aggregator = NULL;
|
1720 |
|
|
port->next_port_in_aggregator = NULL;
|
1721 |
|
|
port->transaction_id = 0;
|
1722 |
|
|
|
1723 |
|
|
ad_initialize_lacpdu(&(port->lacpdu));
|
1724 |
|
|
}
|
1725 |
|
|
}
|
1726 |
|
|
|
1727 |
|
|
/**
|
1728 |
|
|
* ad_enable_collecting_distributing - enable a port's transmit/receive
|
1729 |
|
|
* @port: the port we're looking at
|
1730 |
|
|
*
|
1731 |
|
|
* Enable @port if it's in an active aggregator
|
1732 |
|
|
*/
|
1733 |
|
|
static void ad_enable_collecting_distributing(struct port *port)
|
1734 |
|
|
{
|
1735 |
|
|
if (port->aggregator->is_active) {
|
1736 |
|
|
dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
|
1737 |
|
|
__enable_port(port);
|
1738 |
|
|
}
|
1739 |
|
|
}
|
1740 |
|
|
|
1741 |
|
|
/**
|
1742 |
|
|
* ad_disable_collecting_distributing - disable a port's transmit/receive
|
1743 |
|
|
* @port: the port we're looking at
|
1744 |
|
|
*
|
1745 |
|
|
*/
|
1746 |
|
|
static void ad_disable_collecting_distributing(struct port *port)
|
1747 |
|
|
{
|
1748 |
|
|
if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) {
|
1749 |
|
|
dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
|
1750 |
|
|
__disable_port(port);
|
1751 |
|
|
}
|
1752 |
|
|
}
|
1753 |
|
|
|
1754 |
|
|
#if 0
|
1755 |
|
|
/**
|
1756 |
|
|
* ad_marker_info_send - send a marker information frame
|
1757 |
|
|
* @port: the port we're looking at
|
1758 |
|
|
*
|
1759 |
|
|
* This function does nothing since we decided not to implement send and handle
|
1760 |
|
|
* response for marker PDU's, in this stage, but only to respond to marker
|
1761 |
|
|
* information.
|
1762 |
|
|
*/
|
1763 |
|
|
static void ad_marker_info_send(struct port *port)
|
1764 |
|
|
{
|
1765 |
|
|
struct marker marker;
|
1766 |
|
|
u16 index;
|
1767 |
|
|
|
1768 |
|
|
// fill the marker PDU with the appropriate values
|
1769 |
|
|
marker.subtype = 0x02;
|
1770 |
|
|
marker.version_number = 0x01;
|
1771 |
|
|
marker.tlv_type = AD_MARKER_INFORMATION_SUBTYPE;
|
1772 |
|
|
marker.marker_length = 0x16;
|
1773 |
|
|
// convert requester_port to Big Endian
|
1774 |
|
|
marker.requester_port = (((port->actor_port_number & 0xFF) << 8) |((u16)(port->actor_port_number & 0xFF00) >> 8));
|
1775 |
|
|
marker.requester_system = port->actor_system;
|
1776 |
|
|
// convert requester_port(u32) to Big Endian
|
1777 |
|
|
marker.requester_transaction_id = (((++port->transaction_id & 0xFF) << 24) |((port->transaction_id & 0xFF00) << 8) |((port->transaction_id & 0xFF0000) >> 8) |((port->transaction_id & 0xFF000000) >> 24));
|
1778 |
|
|
marker.pad = 0;
|
1779 |
|
|
marker.tlv_type_terminator = 0x00;
|
1780 |
|
|
marker.terminator_length = 0x00;
|
1781 |
|
|
for (index=0; index<90; index++) {
|
1782 |
|
|
marker.reserved_90[index]=0;
|
1783 |
|
|
}
|
1784 |
|
|
|
1785 |
|
|
// send the marker information
|
1786 |
|
|
if (ad_marker_send(port, &marker) >= 0) {
|
1787 |
|
|
dprintk("Sent Marker Information on port %d\n", port->actor_port_number);
|
1788 |
|
|
}
|
1789 |
|
|
}
|
1790 |
|
|
#endif
|
1791 |
|
|
|
1792 |
|
|
/**
|
1793 |
|
|
* ad_marker_info_received - handle receive of a Marker information frame
|
1794 |
|
|
* @marker_info: Marker info received
|
1795 |
|
|
* @port: the port we're looking at
|
1796 |
|
|
*
|
1797 |
|
|
*/
|
1798 |
|
|
static void ad_marker_info_received(struct marker *marker_info,struct port *port)
|
1799 |
|
|
{
|
1800 |
|
|
struct marker marker;
|
1801 |
|
|
|
1802 |
|
|
// copy the received marker data to the response marker
|
1803 |
|
|
//marker = *marker_info;
|
1804 |
|
|
memcpy(&marker, marker_info, sizeof(struct marker));
|
1805 |
|
|
// change the marker subtype to marker response
|
1806 |
|
|
marker.tlv_type=AD_MARKER_RESPONSE_SUBTYPE;
|
1807 |
|
|
// send the marker response
|
1808 |
|
|
|
1809 |
|
|
if (ad_marker_send(port, &marker) >= 0) {
|
1810 |
|
|
dprintk("Sent Marker Response on port %d\n", port->actor_port_number);
|
1811 |
|
|
}
|
1812 |
|
|
}
|
1813 |
|
|
|
1814 |
|
|
/**
|
1815 |
|
|
* ad_marker_response_received - handle receive of a marker response frame
|
1816 |
|
|
* @marker: marker PDU received
|
1817 |
|
|
* @port: the port we're looking at
|
1818 |
|
|
*
|
1819 |
|
|
* This function does nothing since we decided not to implement send and handle
|
1820 |
|
|
* response for marker PDU's, in this stage, but only to respond to marker
|
1821 |
|
|
* information.
|
1822 |
|
|
*/
|
1823 |
|
|
static void ad_marker_response_received(struct marker *marker, struct port *port)
|
1824 |
|
|
{
|
1825 |
|
|
marker=NULL; // just to satisfy the compiler
|
1826 |
|
|
port=NULL; // just to satisfy the compiler
|
1827 |
|
|
// DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW
|
1828 |
|
|
}
|
1829 |
|
|
|
1830 |
|
|
/**
|
1831 |
|
|
* ad_initialize_lacpdu - initialize a given lacpdu structure
|
1832 |
|
|
* @lacpdu: lacpdu structure to initialize
|
1833 |
|
|
*
|
1834 |
|
|
*/
|
1835 |
|
|
static void ad_initialize_lacpdu(struct lacpdu *lacpdu)
|
1836 |
|
|
{
|
1837 |
|
|
u16 index;
|
1838 |
|
|
|
1839 |
|
|
// initialize lacpdu data
|
1840 |
|
|
lacpdu->subtype = 0x01;
|
1841 |
|
|
lacpdu->version_number = 0x01;
|
1842 |
|
|
lacpdu->tlv_type_actor_info = 0x01;
|
1843 |
|
|
lacpdu->actor_information_length = 0x14;
|
1844 |
|
|
// lacpdu->actor_system_priority updated on send
|
1845 |
|
|
// lacpdu->actor_system updated on send
|
1846 |
|
|
// lacpdu->actor_key updated on send
|
1847 |
|
|
// lacpdu->actor_port_priority updated on send
|
1848 |
|
|
// lacpdu->actor_port updated on send
|
1849 |
|
|
// lacpdu->actor_state updated on send
|
1850 |
|
|
lacpdu->tlv_type_partner_info = 0x02;
|
1851 |
|
|
lacpdu->partner_information_length = 0x14;
|
1852 |
|
|
for (index=0; index<=2; index++) {
|
1853 |
|
|
lacpdu->reserved_3_1[index]=0;
|
1854 |
|
|
}
|
1855 |
|
|
// lacpdu->partner_system_priority updated on send
|
1856 |
|
|
// lacpdu->partner_system updated on send
|
1857 |
|
|
// lacpdu->partner_key updated on send
|
1858 |
|
|
// lacpdu->partner_port_priority updated on send
|
1859 |
|
|
// lacpdu->partner_port updated on send
|
1860 |
|
|
// lacpdu->partner_state updated on send
|
1861 |
|
|
for (index=0; index<=2; index++) {
|
1862 |
|
|
lacpdu->reserved_3_2[index]=0;
|
1863 |
|
|
}
|
1864 |
|
|
lacpdu->tlv_type_collector_info = 0x03;
|
1865 |
|
|
lacpdu->collector_information_length= 0x10;
|
1866 |
|
|
lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY;
|
1867 |
|
|
for (index=0; index<=11; index++) {
|
1868 |
|
|
lacpdu->reserved_12[index]=0;
|
1869 |
|
|
}
|
1870 |
|
|
lacpdu->tlv_type_terminator = 0x00;
|
1871 |
|
|
lacpdu->terminator_length = 0;
|
1872 |
|
|
for (index=0; index<=49; index++) {
|
1873 |
|
|
lacpdu->reserved_50[index]=0;
|
1874 |
|
|
}
|
1875 |
|
|
}
|
1876 |
|
|
|
1877 |
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
1878 |
|
|
// ================= AD exported functions to the main bonding code ==================
|
1879 |
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
1880 |
|
|
|
1881 |
|
|
// Check aggregators status in team every T seconds
|
1882 |
|
|
#define AD_AGGREGATOR_SELECTION_TIMER 8
|
1883 |
|
|
|
1884 |
|
|
static u16 aggregator_identifier;
|
1885 |
|
|
|
1886 |
|
|
/**
|
1887 |
|
|
* bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures
|
1888 |
|
|
* @bond: bonding struct to work on
|
1889 |
|
|
* @tick_resolution: tick duration (millisecond resolution)
|
1890 |
|
|
* @lacp_fast: boolean. whether fast periodic should be used
|
1891 |
|
|
*
|
1892 |
|
|
* Can be called only after the mac address of the bond is set.
|
1893 |
|
|
*/
|
1894 |
|
|
void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast)
|
1895 |
|
|
{
|
1896 |
|
|
// check that the bond is not initialized yet
|
1897 |
|
|
if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->dev->dev_addr))) {
|
1898 |
|
|
|
1899 |
|
|
aggregator_identifier = 0;
|
1900 |
|
|
|
1901 |
|
|
BOND_AD_INFO(bond).lacp_fast = lacp_fast;
|
1902 |
|
|
BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
|
1903 |
|
|
BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
|
1904 |
|
|
|
1905 |
|
|
// initialize how many times this module is called in one second(should be about every 100ms)
|
1906 |
|
|
ad_ticks_per_sec = tick_resolution;
|
1907 |
|
|
|
1908 |
|
|
// initialize the aggregator selection timer(to activate an aggregation selection after initialize)
|
1909 |
|
|
BOND_AD_INFO(bond).agg_select_timer = (AD_AGGREGATOR_SELECTION_TIMER * ad_ticks_per_sec);
|
1910 |
|
|
BOND_AD_INFO(bond).agg_select_mode = AD_BANDWIDTH;
|
1911 |
|
|
}
|
1912 |
|
|
}
|
1913 |
|
|
|
1914 |
|
|
/**
|
1915 |
|
|
* bond_3ad_bind_slave - initialize a slave's port
|
1916 |
|
|
* @slave: slave struct to work on
|
1917 |
|
|
*
|
1918 |
|
|
* Returns: 0 on success
|
1919 |
|
|
* < 0 on error
|
1920 |
|
|
*/
|
1921 |
|
|
int bond_3ad_bind_slave(struct slave *slave)
|
1922 |
|
|
{
|
1923 |
|
|
struct bonding *bond = bond_get_bond_by_slave(slave);
|
1924 |
|
|
struct port *port;
|
1925 |
|
|
struct aggregator *aggregator;
|
1926 |
|
|
|
1927 |
|
|
if (bond == NULL) {
|
1928 |
|
|
printk(KERN_ERR "The slave %s is not attached to its bond\n", slave->dev->name);
|
1929 |
|
|
return -1;
|
1930 |
|
|
}
|
1931 |
|
|
|
1932 |
|
|
//check that the slave has not been intialized yet.
|
1933 |
|
|
if (SLAVE_AD_INFO(slave).port.slave != slave) {
|
1934 |
|
|
|
1935 |
|
|
// port initialization
|
1936 |
|
|
port = &(SLAVE_AD_INFO(slave).port);
|
1937 |
|
|
|
1938 |
|
|
ad_initialize_port(port, BOND_AD_INFO(bond).lacp_fast);
|
1939 |
|
|
|
1940 |
|
|
port->slave = slave;
|
1941 |
|
|
port->actor_port_number = SLAVE_AD_INFO(slave).id;
|
1942 |
|
|
// key is determined according to the link speed, duplex and user key(which is yet not supported)
|
1943 |
|
|
// ------------------------------------------------------------
|
1944 |
|
|
// Port key : | User key | Speed |Duplex|
|
1945 |
|
|
// ------------------------------------------------------------
|
1946 |
|
|
// 16 6 1 0
|
1947 |
|
|
port->actor_admin_port_key = 0; // initialize this parameter
|
1948 |
|
|
port->actor_admin_port_key |= __get_duplex(port);
|
1949 |
|
|
port->actor_admin_port_key |= (__get_link_speed(port) << 1);
|
1950 |
|
|
port->actor_oper_port_key = port->actor_admin_port_key;
|
1951 |
|
|
// if the port is not full duplex, then the port should be not lacp Enabled
|
1952 |
|
|
if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) {
|
1953 |
|
|
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
|
1954 |
|
|
}
|
1955 |
|
|
// actor system is the bond's system
|
1956 |
|
|
port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
|
1957 |
|
|
// tx timer(to verify that no more than MAX_TX_IN_SECOND lacpdu's are sent in one second)
|
1958 |
|
|
port->sm_tx_timer_counter = ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
|
1959 |
|
|
port->aggregator = NULL;
|
1960 |
|
|
port->next_port_in_aggregator = NULL;
|
1961 |
|
|
|
1962 |
|
|
__disable_port(port);
|
1963 |
|
|
__initialize_port_locks(port);
|
1964 |
|
|
|
1965 |
|
|
|
1966 |
|
|
// aggregator initialization
|
1967 |
|
|
aggregator = &(SLAVE_AD_INFO(slave).aggregator);
|
1968 |
|
|
|
1969 |
|
|
ad_initialize_agg(aggregator);
|
1970 |
|
|
|
1971 |
|
|
aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr);
|
1972 |
|
|
aggregator->aggregator_identifier = (++aggregator_identifier);
|
1973 |
|
|
aggregator->slave = slave;
|
1974 |
|
|
aggregator->is_active = 0;
|
1975 |
|
|
aggregator->num_of_ports = 0;
|
1976 |
|
|
}
|
1977 |
|
|
|
1978 |
|
|
return 0;
|
1979 |
|
|
}
|
1980 |
|
|
|
1981 |
|
|
/**
|
1982 |
|
|
* bond_3ad_unbind_slave - deinitialize a slave's port
|
1983 |
|
|
* @slave: slave struct to work on
|
1984 |
|
|
*
|
1985 |
|
|
* Search for the aggregator that is related to this port, remove the
|
1986 |
|
|
* aggregator and assign another aggregator for other port related to it
|
1987 |
|
|
* (if any), and remove the port.
|
1988 |
|
|
*/
|
1989 |
|
|
void bond_3ad_unbind_slave(struct slave *slave)
|
1990 |
|
|
{
|
1991 |
|
|
struct port *port, *prev_port, *temp_port;
|
1992 |
|
|
struct aggregator *aggregator, *new_aggregator, *temp_aggregator;
|
1993 |
|
|
int select_new_active_agg = 0;
|
1994 |
|
|
|
1995 |
|
|
// find the aggregator related to this slave
|
1996 |
|
|
aggregator = &(SLAVE_AD_INFO(slave).aggregator);
|
1997 |
|
|
|
1998 |
|
|
// find the port related to this slave
|
1999 |
|
|
port = &(SLAVE_AD_INFO(slave).port);
|
2000 |
|
|
|
2001 |
|
|
// if slave is null, the whole port is not initialized
|
2002 |
|
|
if (!port->slave) {
|
2003 |
|
|
printk(KERN_WARNING DRV_NAME ": Trying to unbind an uninitialized port on %s\n", slave->dev->name);
|
2004 |
|
|
return;
|
2005 |
|
|
}
|
2006 |
|
|
|
2007 |
|
|
dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier);
|
2008 |
|
|
|
2009 |
|
|
/* Tell the partner that this port is not suitable for aggregation */
|
2010 |
|
|
port->actor_oper_port_state &= ~AD_STATE_AGGREGATION;
|
2011 |
|
|
__update_lacpdu_from_port(port);
|
2012 |
|
|
ad_lacpdu_send(port);
|
2013 |
|
|
|
2014 |
|
|
// check if this aggregator is occupied
|
2015 |
|
|
if (aggregator->lag_ports) {
|
2016 |
|
|
// check if there are other ports related to this aggregator except
|
2017 |
|
|
// the port related to this slave(thats ensure us that there is a
|
2018 |
|
|
// reason to search for new aggregator, and that we will find one
|
2019 |
|
|
if ((aggregator->lag_ports != port) || (aggregator->lag_ports->next_port_in_aggregator)) {
|
2020 |
|
|
// find new aggregator for the related port(s)
|
2021 |
|
|
new_aggregator = __get_first_agg(port);
|
2022 |
|
|
for (; new_aggregator; new_aggregator = __get_next_agg(new_aggregator)) {
|
2023 |
|
|
// if the new aggregator is empty, or it connected to to our port only
|
2024 |
|
|
if (!new_aggregator->lag_ports || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator)) {
|
2025 |
|
|
break;
|
2026 |
|
|
}
|
2027 |
|
|
}
|
2028 |
|
|
// if new aggregator found, copy the aggregator's parameters
|
2029 |
|
|
// and connect the related lag_ports to the new aggregator
|
2030 |
|
|
if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) {
|
2031 |
|
|
dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier);
|
2032 |
|
|
|
2033 |
|
|
if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
|
2034 |
|
|
printk(KERN_INFO DRV_NAME ": Removing an active aggregator\n");
|
2035 |
|
|
// select new active aggregator
|
2036 |
|
|
select_new_active_agg = 1;
|
2037 |
|
|
}
|
2038 |
|
|
|
2039 |
|
|
new_aggregator->is_individual = aggregator->is_individual;
|
2040 |
|
|
new_aggregator->actor_admin_aggregator_key = aggregator->actor_admin_aggregator_key;
|
2041 |
|
|
new_aggregator->actor_oper_aggregator_key = aggregator->actor_oper_aggregator_key;
|
2042 |
|
|
new_aggregator->partner_system = aggregator->partner_system;
|
2043 |
|
|
new_aggregator->partner_system_priority = aggregator->partner_system_priority;
|
2044 |
|
|
new_aggregator->partner_oper_aggregator_key = aggregator->partner_oper_aggregator_key;
|
2045 |
|
|
new_aggregator->receive_state = aggregator->receive_state;
|
2046 |
|
|
new_aggregator->transmit_state = aggregator->transmit_state;
|
2047 |
|
|
new_aggregator->lag_ports = aggregator->lag_ports;
|
2048 |
|
|
new_aggregator->is_active = aggregator->is_active;
|
2049 |
|
|
new_aggregator->num_of_ports = aggregator->num_of_ports;
|
2050 |
|
|
|
2051 |
|
|
// update the information that is written on the ports about the aggregator
|
2052 |
|
|
for (temp_port=aggregator->lag_ports; temp_port; temp_port=temp_port->next_port_in_aggregator) {
|
2053 |
|
|
temp_port->aggregator=new_aggregator;
|
2054 |
|
|
temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier;
|
2055 |
|
|
}
|
2056 |
|
|
|
2057 |
|
|
// clear the aggregator
|
2058 |
|
|
ad_clear_agg(aggregator);
|
2059 |
|
|
|
2060 |
|
|
if (select_new_active_agg) {
|
2061 |
|
|
ad_agg_selection_logic(__get_first_agg(port));
|
2062 |
|
|
}
|
2063 |
|
|
} else {
|
2064 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: unbinding aggregator, "
|
2065 |
|
|
"and could not find a new aggregator for its ports\n");
|
2066 |
|
|
}
|
2067 |
|
|
} else { // in case that the only port related to this aggregator is the one we want to remove
|
2068 |
|
|
select_new_active_agg = aggregator->is_active;
|
2069 |
|
|
// clear the aggregator
|
2070 |
|
|
ad_clear_agg(aggregator);
|
2071 |
|
|
if (select_new_active_agg) {
|
2072 |
|
|
printk(KERN_INFO "Removing an active aggregator\n");
|
2073 |
|
|
// select new active aggregator
|
2074 |
|
|
ad_agg_selection_logic(__get_first_agg(port));
|
2075 |
|
|
}
|
2076 |
|
|
}
|
2077 |
|
|
}
|
2078 |
|
|
|
2079 |
|
|
dprintk("Unbinding port %d\n", port->actor_port_number);
|
2080 |
|
|
// find the aggregator that this port is connected to
|
2081 |
|
|
temp_aggregator = __get_first_agg(port);
|
2082 |
|
|
for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) {
|
2083 |
|
|
prev_port = NULL;
|
2084 |
|
|
// search the port in the aggregator's related ports
|
2085 |
|
|
for (temp_port=temp_aggregator->lag_ports; temp_port; prev_port=temp_port, temp_port=temp_port->next_port_in_aggregator) {
|
2086 |
|
|
if (temp_port == port) { // the aggregator found - detach the port from this aggregator
|
2087 |
|
|
if (prev_port) {
|
2088 |
|
|
prev_port->next_port_in_aggregator = temp_port->next_port_in_aggregator;
|
2089 |
|
|
} else {
|
2090 |
|
|
temp_aggregator->lag_ports = temp_port->next_port_in_aggregator;
|
2091 |
|
|
}
|
2092 |
|
|
temp_aggregator->num_of_ports--;
|
2093 |
|
|
if (temp_aggregator->num_of_ports==0) {
|
2094 |
|
|
select_new_active_agg = temp_aggregator->is_active;
|
2095 |
|
|
// clear the aggregator
|
2096 |
|
|
ad_clear_agg(temp_aggregator);
|
2097 |
|
|
if (select_new_active_agg) {
|
2098 |
|
|
printk(KERN_INFO "Removing an active aggregator\n");
|
2099 |
|
|
// select new active aggregator
|
2100 |
|
|
ad_agg_selection_logic(__get_first_agg(port));
|
2101 |
|
|
}
|
2102 |
|
|
}
|
2103 |
|
|
break;
|
2104 |
|
|
}
|
2105 |
|
|
}
|
2106 |
|
|
}
|
2107 |
|
|
port->slave=NULL;
|
2108 |
|
|
}
|
2109 |
|
|
|
2110 |
|
|
/**
|
2111 |
|
|
* bond_3ad_state_machine_handler - handle state machines timeout
|
2112 |
|
|
* @bond: bonding struct to work on
|
2113 |
|
|
*
|
2114 |
|
|
* The state machine handling concept in this module is to check every tick
|
2115 |
|
|
* which state machine should operate any function. The execution order is
|
2116 |
|
|
* round robin, so when we have an interaction between state machines, the
|
2117 |
|
|
* reply of one to each other might be delayed until next tick.
|
2118 |
|
|
*
|
2119 |
|
|
* This function also complete the initialization when the agg_select_timer
|
2120 |
|
|
* times out, and it selects an aggregator for the ports that are yet not
|
2121 |
|
|
* related to any aggregator, and selects the active aggregator for a bond.
|
2122 |
|
|
*/
|
2123 |
|
|
void bond_3ad_state_machine_handler(struct bonding *bond)
|
2124 |
|
|
{
|
2125 |
|
|
struct port *port;
|
2126 |
|
|
struct aggregator *aggregator;
|
2127 |
|
|
|
2128 |
|
|
read_lock(&bond->lock);
|
2129 |
|
|
|
2130 |
|
|
if (bond->kill_timers) {
|
2131 |
|
|
goto out;
|
2132 |
|
|
}
|
2133 |
|
|
|
2134 |
|
|
//check if there are any slaves
|
2135 |
|
|
if (bond->slave_cnt == 0) {
|
2136 |
|
|
goto re_arm;
|
2137 |
|
|
}
|
2138 |
|
|
|
2139 |
|
|
// check if agg_select_timer timer after initialize is timed out
|
2140 |
|
|
if (BOND_AD_INFO(bond).agg_select_timer && !(--BOND_AD_INFO(bond).agg_select_timer)) {
|
2141 |
|
|
// select the active aggregator for the bond
|
2142 |
|
|
if ((port = __get_first_port(bond))) {
|
2143 |
|
|
if (!port->slave) {
|
2144 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: bond's first port is uninitialized\n");
|
2145 |
|
|
goto re_arm;
|
2146 |
|
|
}
|
2147 |
|
|
|
2148 |
|
|
aggregator = __get_first_agg(port);
|
2149 |
|
|
ad_agg_selection_logic(aggregator);
|
2150 |
|
|
}
|
2151 |
|
|
}
|
2152 |
|
|
|
2153 |
|
|
// for each port run the state machines
|
2154 |
|
|
for (port = __get_first_port(bond); port; port = __get_next_port(port)) {
|
2155 |
|
|
if (!port->slave) {
|
2156 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: Found an uninitialized port\n");
|
2157 |
|
|
goto re_arm;
|
2158 |
|
|
}
|
2159 |
|
|
|
2160 |
|
|
ad_rx_machine(NULL, port);
|
2161 |
|
|
ad_periodic_machine(port);
|
2162 |
|
|
ad_port_selection_logic(port);
|
2163 |
|
|
ad_mux_machine(port);
|
2164 |
|
|
ad_tx_machine(port);
|
2165 |
|
|
|
2166 |
|
|
// turn off the BEGIN bit, since we already handled it
|
2167 |
|
|
if (port->sm_vars & AD_PORT_BEGIN) {
|
2168 |
|
|
port->sm_vars &= ~AD_PORT_BEGIN;
|
2169 |
|
|
}
|
2170 |
|
|
}
|
2171 |
|
|
|
2172 |
|
|
re_arm:
|
2173 |
|
|
mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks);
|
2174 |
|
|
out:
|
2175 |
|
|
read_unlock(&bond->lock);
|
2176 |
|
|
}
|
2177 |
|
|
|
2178 |
|
|
/**
|
2179 |
|
|
* bond_3ad_rx_indication - handle a received frame
|
2180 |
|
|
* @lacpdu: received lacpdu
|
2181 |
|
|
* @slave: slave struct to work on
|
2182 |
|
|
* @length: length of the data received
|
2183 |
|
|
*
|
2184 |
|
|
* It is assumed that frames that were sent on this NIC don't returned as new
|
2185 |
|
|
* received frames (loopback). Since only the payload is given to this
|
2186 |
|
|
* function, it check for loopback.
|
2187 |
|
|
*/
|
2188 |
|
|
void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length)
|
2189 |
|
|
{
|
2190 |
|
|
struct port *port;
|
2191 |
|
|
|
2192 |
|
|
if (length >= sizeof(struct lacpdu)) {
|
2193 |
|
|
|
2194 |
|
|
port = &(SLAVE_AD_INFO(slave).port);
|
2195 |
|
|
|
2196 |
|
|
if (!port->slave) {
|
2197 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: port of slave %s is uninitialized\n", slave->dev->name);
|
2198 |
|
|
return;
|
2199 |
|
|
}
|
2200 |
|
|
|
2201 |
|
|
switch (lacpdu->subtype) {
|
2202 |
|
|
case AD_TYPE_LACPDU:
|
2203 |
|
|
__ntohs_lacpdu(lacpdu);
|
2204 |
|
|
dprintk("Received LACPDU on port %d\n", port->actor_port_number);
|
2205 |
|
|
ad_rx_machine(lacpdu, port);
|
2206 |
|
|
break;
|
2207 |
|
|
|
2208 |
|
|
case AD_TYPE_MARKER:
|
2209 |
|
|
// No need to convert fields to Little Endian since we don't use the marker's fields.
|
2210 |
|
|
|
2211 |
|
|
switch (((struct marker *)lacpdu)->tlv_type) {
|
2212 |
|
|
case AD_MARKER_INFORMATION_SUBTYPE:
|
2213 |
|
|
dprintk("Received Marker Information on port %d\n", port->actor_port_number);
|
2214 |
|
|
ad_marker_info_received((struct marker *)lacpdu, port);
|
2215 |
|
|
break;
|
2216 |
|
|
|
2217 |
|
|
case AD_MARKER_RESPONSE_SUBTYPE:
|
2218 |
|
|
dprintk("Received Marker Response on port %d\n", port->actor_port_number);
|
2219 |
|
|
ad_marker_response_received((struct marker *)lacpdu, port);
|
2220 |
|
|
break;
|
2221 |
|
|
|
2222 |
|
|
default:
|
2223 |
|
|
dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number);
|
2224 |
|
|
}
|
2225 |
|
|
}
|
2226 |
|
|
}
|
2227 |
|
|
}
|
2228 |
|
|
|
2229 |
|
|
/**
|
2230 |
|
|
* bond_3ad_adapter_speed_changed - handle a slave's speed change indication
|
2231 |
|
|
* @slave: slave struct to work on
|
2232 |
|
|
*
|
2233 |
|
|
* Handle reselection of aggregator (if needed) for this port.
|
2234 |
|
|
*/
|
2235 |
|
|
void bond_3ad_adapter_speed_changed(struct slave *slave)
|
2236 |
|
|
{
|
2237 |
|
|
struct port *port;
|
2238 |
|
|
|
2239 |
|
|
port = &(SLAVE_AD_INFO(slave).port);
|
2240 |
|
|
|
2241 |
|
|
// if slave is null, the whole port is not initialized
|
2242 |
|
|
if (!port->slave) {
|
2243 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: speed changed for uninitialized port on %s\n",
|
2244 |
|
|
slave->dev->name);
|
2245 |
|
|
return;
|
2246 |
|
|
}
|
2247 |
|
|
|
2248 |
|
|
port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS;
|
2249 |
|
|
port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1);
|
2250 |
|
|
dprintk("Port %d changed speed\n", port->actor_port_number);
|
2251 |
|
|
// there is no need to reselect a new aggregator, just signal the
|
2252 |
|
|
// state machines to reinitialize
|
2253 |
|
|
port->sm_vars |= AD_PORT_BEGIN;
|
2254 |
|
|
}
|
2255 |
|
|
|
2256 |
|
|
/**
|
2257 |
|
|
* bond_3ad_adapter_duplex_changed - handle a slave's duplex change indication
|
2258 |
|
|
* @slave: slave struct to work on
|
2259 |
|
|
*
|
2260 |
|
|
* Handle reselection of aggregator (if needed) for this port.
|
2261 |
|
|
*/
|
2262 |
|
|
void bond_3ad_adapter_duplex_changed(struct slave *slave)
|
2263 |
|
|
{
|
2264 |
|
|
struct port *port;
|
2265 |
|
|
|
2266 |
|
|
port=&(SLAVE_AD_INFO(slave).port);
|
2267 |
|
|
|
2268 |
|
|
// if slave is null, the whole port is not initialized
|
2269 |
|
|
if (!port->slave) {
|
2270 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: duplex changed for uninitialized port on %s\n",
|
2271 |
|
|
slave->dev->name);
|
2272 |
|
|
return;
|
2273 |
|
|
}
|
2274 |
|
|
|
2275 |
|
|
port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
|
2276 |
|
|
port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port);
|
2277 |
|
|
dprintk("Port %d changed duplex\n", port->actor_port_number);
|
2278 |
|
|
// there is no need to reselect a new aggregator, just signal the
|
2279 |
|
|
// state machines to reinitialize
|
2280 |
|
|
port->sm_vars |= AD_PORT_BEGIN;
|
2281 |
|
|
}
|
2282 |
|
|
|
2283 |
|
|
/**
|
2284 |
|
|
* bond_3ad_handle_link_change - handle a slave's link status change indication
|
2285 |
|
|
* @slave: slave struct to work on
|
2286 |
|
|
* @status: whether the link is now up or down
|
2287 |
|
|
*
|
2288 |
|
|
* Handle reselection of aggregator (if needed) for this port.
|
2289 |
|
|
*/
|
2290 |
|
|
void bond_3ad_handle_link_change(struct slave *slave, char link)
|
2291 |
|
|
{
|
2292 |
|
|
struct port *port;
|
2293 |
|
|
|
2294 |
|
|
port = &(SLAVE_AD_INFO(slave).port);
|
2295 |
|
|
|
2296 |
|
|
// if slave is null, the whole port is not initialized
|
2297 |
|
|
if (!port->slave) {
|
2298 |
|
|
printk(KERN_WARNING DRV_NAME ": Warning: link status changed for uninitialized port on %s\n",
|
2299 |
|
|
slave->dev->name);
|
2300 |
|
|
return;
|
2301 |
|
|
}
|
2302 |
|
|
|
2303 |
|
|
// on link down we are zeroing duplex and speed since some of the adaptors(ce1000.lan) report full duplex/speed instead of N/A(duplex) / 0(speed)
|
2304 |
|
|
// on link up we are forcing recheck on the duplex and speed since some of he adaptors(ce1000.lan) report
|
2305 |
|
|
if (link == BOND_LINK_UP) {
|
2306 |
|
|
port->is_enabled = 1;
|
2307 |
|
|
port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
|
2308 |
|
|
port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port);
|
2309 |
|
|
port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS;
|
2310 |
|
|
port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1);
|
2311 |
|
|
} else {
|
2312 |
|
|
/* link has failed */
|
2313 |
|
|
port->is_enabled = 0;
|
2314 |
|
|
port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
|
2315 |
|
|
port->actor_oper_port_key= (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS);
|
2316 |
|
|
}
|
2317 |
|
|
//BOND_PRINT_DBG(("Port %d changed link status to %s", port->actor_port_number, ((link == BOND_LINK_UP)?"UP":"DOWN")));
|
2318 |
|
|
// there is no need to reselect a new aggregator, just signal the
|
2319 |
|
|
// state machines to reinitialize
|
2320 |
|
|
port->sm_vars |= AD_PORT_BEGIN;
|
2321 |
|
|
}
|
2322 |
|
|
|
2323 |
|
|
/**
|
2324 |
|
|
* bond_3ad_get_active_agg_info - get information of the active aggregator
|
2325 |
|
|
* @bond: bonding struct to work on
|
2326 |
|
|
* @ad_info: ad_info struct to fill with the bond's info
|
2327 |
|
|
*
|
2328 |
|
|
* Returns: 0 on success
|
2329 |
|
|
* < 0 on error
|
2330 |
|
|
*/
|
2331 |
|
|
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
|
2332 |
|
|
{
|
2333 |
|
|
struct aggregator *aggregator = NULL;
|
2334 |
|
|
struct port *port;
|
2335 |
|
|
|
2336 |
|
|
for (port = __get_first_port(bond); port; port = __get_next_port(port)) {
|
2337 |
|
|
if (port->aggregator && port->aggregator->is_active) {
|
2338 |
|
|
aggregator = port->aggregator;
|
2339 |
|
|
break;
|
2340 |
|
|
}
|
2341 |
|
|
}
|
2342 |
|
|
|
2343 |
|
|
if (aggregator) {
|
2344 |
|
|
ad_info->aggregator_id = aggregator->aggregator_identifier;
|
2345 |
|
|
ad_info->ports = aggregator->num_of_ports;
|
2346 |
|
|
ad_info->actor_key = aggregator->actor_oper_aggregator_key;
|
2347 |
|
|
ad_info->partner_key = aggregator->partner_oper_aggregator_key;
|
2348 |
|
|
memcpy(ad_info->partner_system, aggregator->partner_system.mac_addr_value, ETH_ALEN);
|
2349 |
|
|
return 0;
|
2350 |
|
|
}
|
2351 |
|
|
|
2352 |
|
|
return -1;
|
2353 |
|
|
}
|
2354 |
|
|
|
2355 |
|
|
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
|
2356 |
|
|
{
|
2357 |
|
|
struct slave *slave, *start_at;
|
2358 |
|
|
struct bonding *bond = dev->priv;
|
2359 |
|
|
struct ethhdr *data = (struct ethhdr *)skb->data;
|
2360 |
|
|
int slave_agg_no;
|
2361 |
|
|
int slaves_in_agg;
|
2362 |
|
|
int agg_id;
|
2363 |
|
|
int i;
|
2364 |
|
|
struct ad_info ad_info;
|
2365 |
|
|
int res = 1;
|
2366 |
|
|
|
2367 |
|
|
/* make sure that the slaves list will
|
2368 |
|
|
* not change during tx
|
2369 |
|
|
*/
|
2370 |
|
|
read_lock(&bond->lock);
|
2371 |
|
|
|
2372 |
|
|
if (!BOND_IS_OK(bond)) {
|
2373 |
|
|
goto out;
|
2374 |
|
|
}
|
2375 |
|
|
|
2376 |
|
|
if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
|
2377 |
|
|
printk(KERN_DEBUG "ERROR: bond_3ad_get_active_agg_info failed\n");
|
2378 |
|
|
goto out;
|
2379 |
|
|
}
|
2380 |
|
|
|
2381 |
|
|
slaves_in_agg = ad_info.ports;
|
2382 |
|
|
agg_id = ad_info.aggregator_id;
|
2383 |
|
|
|
2384 |
|
|
if (slaves_in_agg == 0) {
|
2385 |
|
|
/*the aggregator is empty*/
|
2386 |
|
|
printk(KERN_DEBUG "ERROR: active aggregator is empty\n");
|
2387 |
|
|
goto out;
|
2388 |
|
|
}
|
2389 |
|
|
|
2390 |
|
|
slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg;
|
2391 |
|
|
|
2392 |
|
|
bond_for_each_slave(bond, slave, i) {
|
2393 |
|
|
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
|
2394 |
|
|
|
2395 |
|
|
if (agg && (agg->aggregator_identifier == agg_id)) {
|
2396 |
|
|
slave_agg_no--;
|
2397 |
|
|
if (slave_agg_no < 0) {
|
2398 |
|
|
break;
|
2399 |
|
|
}
|
2400 |
|
|
}
|
2401 |
|
|
}
|
2402 |
|
|
|
2403 |
|
|
if (slave_agg_no >= 0) {
|
2404 |
|
|
printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id);
|
2405 |
|
|
goto out;
|
2406 |
|
|
}
|
2407 |
|
|
|
2408 |
|
|
start_at = slave;
|
2409 |
|
|
|
2410 |
|
|
bond_for_each_slave_from(bond, slave, i, start_at) {
|
2411 |
|
|
int slave_agg_id = 0;
|
2412 |
|
|
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
|
2413 |
|
|
|
2414 |
|
|
if (agg) {
|
2415 |
|
|
slave_agg_id = agg->aggregator_identifier;
|
2416 |
|
|
}
|
2417 |
|
|
|
2418 |
|
|
if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) {
|
2419 |
|
|
res = bond_dev_queue_xmit(bond, skb, slave->dev);
|
2420 |
|
|
break;
|
2421 |
|
|
}
|
2422 |
|
|
}
|
2423 |
|
|
|
2424 |
|
|
out:
|
2425 |
|
|
if (res) {
|
2426 |
|
|
/* no suitable interface, frame not sent */
|
2427 |
|
|
dev_kfree_skb(skb);
|
2428 |
|
|
}
|
2429 |
|
|
read_unlock(&bond->lock);
|
2430 |
|
|
return 0;
|
2431 |
|
|
}
|
2432 |
|
|
|
2433 |
|
|
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype)
|
2434 |
|
|
{
|
2435 |
|
|
struct bonding *bond = dev->priv;
|
2436 |
|
|
struct slave *slave = NULL;
|
2437 |
|
|
int ret = NET_RX_DROP;
|
2438 |
|
|
|
2439 |
|
|
if (!(dev->flags & IFF_MASTER)) {
|
2440 |
|
|
goto out;
|
2441 |
|
|
}
|
2442 |
|
|
|
2443 |
|
|
read_lock(&bond->lock);
|
2444 |
|
|
slave = bond_get_slave_by_dev((struct bonding *)dev->priv,
|
2445 |
|
|
skb->real_dev);
|
2446 |
|
|
if (slave == NULL) {
|
2447 |
|
|
goto out_unlock;
|
2448 |
|
|
}
|
2449 |
|
|
|
2450 |
|
|
bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
|
2451 |
|
|
|
2452 |
|
|
ret = NET_RX_SUCCESS;
|
2453 |
|
|
|
2454 |
|
|
out_unlock:
|
2455 |
|
|
read_unlock(&bond->lock);
|
2456 |
|
|
out:
|
2457 |
|
|
dev_kfree_skb(skb);
|
2458 |
|
|
|
2459 |
|
|
return ret;
|
2460 |
|
|
}
|
2461 |
|
|
|