Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
83cbd33a
Commit
83cbd33a
authored
Nov 15, 2005
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'bonding-sysfs' of
git://git.tuxdriver.com/git/netdev-jwl
parents
06d61cbf
691b73b1
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1735 additions
and
182 deletions
+1735
-182
drivers/net/bonding/Makefile
drivers/net/bonding/Makefile
+1
-1
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_3ad.c
+47
-27
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_alb.c
+32
-24
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_main.c
+219
-124
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bond_sysfs.c
+1399
-0
drivers/net/bonding/bonding.h
drivers/net/bonding/bonding.h
+33
-4
include/linux/netdevice.h
include/linux/netdevice.h
+1
-0
net/core/dev.c
net/core/dev.c
+2
-1
net/core/utils.c
net/core/utils.c
+1
-1
No files found.
drivers/net/bonding/Makefile
View file @
83cbd33a
...
...
@@ -4,5 +4,5 @@
obj-$(CONFIG_BONDING)
+=
bonding.o
bonding-objs
:=
bond_main.o bond_3ad.o bond_alb.o
bonding-objs
:=
bond_main.o bond_3ad.o bond_alb.o
bond_sysfs.o
drivers/net/bonding/bond_3ad.c
View file @
83cbd33a
...
...
@@ -1198,10 +1198,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
// detect loopback situation
if
(
!
MAC_ADDRESS_COMPARE
(
&
(
lacpdu
->
actor_system
),
&
(
port
->
actor_system
)))
{
// INFO_RECEIVED_LOOPBACK_FRAMES
printk
(
KERN_ERR
DRV_NAME
":
An illegal loopback occurred on adapter (%s)
\n
"
,
port
->
slave
->
dev
->
name
);
printk
(
KERN_ERR
"Check the configuration to verify that all Adapters "
"are connected to 802.3ad compliant switch ports
\n
"
);
printk
(
KERN_ERR
DRV_NAME
":
%s: An illegal loopback occurred on "
"adapter (%s). Check the configuration to verify that all "
"Adapters are connected to 802.3ad compliant switch ports
\n
"
,
port
->
slave
->
dev
->
master
->
name
,
port
->
slave
->
dev
->
name
);
__release_rx_machine_lock
(
port
);
return
;
}
...
...
@@ -1378,8 +1378,9 @@ static void ad_port_selection_logic(struct port *port)
}
}
if
(
!
curr_port
)
{
// meaning: the port was related to an aggregator but was not on the aggregator port list
printk
(
KERN_WARNING
DRV_NAME
": Warning: Port %d (on %s) was "
printk
(
KERN_WARNING
DRV_NAME
":
%s:
Warning: Port %d (on %s) was "
"related to aggregator %d but was not on its port list
\n
"
,
port
->
slave
->
dev
->
master
->
name
,
port
->
actor_port_number
,
port
->
slave
->
dev
->
name
,
port
->
aggregator
->
aggregator_identifier
);
}
...
...
@@ -1450,7 +1451,8 @@ static void ad_port_selection_logic(struct port *port)
dprintk
(
"Port %d joined LAG %d(new LAG)
\n
"
,
port
->
actor_port_number
,
port
->
aggregator
->
aggregator_identifier
);
}
else
{
printk
(
KERN_ERR
DRV_NAME
": Port %d (on %s) did not find a suitable aggregator
\n
"
,
printk
(
KERN_ERR
DRV_NAME
": %s: Port %d (on %s) did not find a suitable aggregator
\n
"
,
port
->
slave
->
dev
->
master
->
name
,
port
->
actor_port_number
,
port
->
slave
->
dev
->
name
);
}
}
...
...
@@ -1582,8 +1584,9 @@ static void ad_agg_selection_logic(struct aggregator *aggregator)
// check if any partner replys
if
(
best_aggregator
->
is_individual
)
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: No 802.3ad response from the link partner "
"for any adapters in the bond
\n
"
);
printk
(
KERN_WARNING
DRV_NAME
": %s: Warning: No 802.3ad response from "
"the link partner for any adapters in the bond
\n
"
,
best_aggregator
->
slave
->
dev
->
master
->
name
);
}
// check if there are more than one aggregator
...
...
@@ -1915,7 +1918,8 @@ int bond_3ad_bind_slave(struct slave *slave)
struct
aggregator
*
aggregator
;
if
(
bond
==
NULL
)
{
printk
(
KERN_ERR
"The slave %s is not attached to its bond
\n
"
,
slave
->
dev
->
name
);
printk
(
KERN_ERR
DRV_NAME
": %s: The slave %s is not attached to its bond
\n
"
,
slave
->
dev
->
master
->
name
,
slave
->
dev
->
name
);
return
-
1
;
}
...
...
@@ -1990,7 +1994,9 @@ void bond_3ad_unbind_slave(struct slave *slave)
// if slave is null, the whole port is not initialized
if
(
!
port
->
slave
)
{
printk
(
KERN_WARNING
DRV_NAME
": Trying to unbind an uninitialized port on %s
\n
"
,
slave
->
dev
->
name
);
printk
(
KERN_WARNING
DRV_NAME
": Warning: %s: Trying to "
"unbind an uninitialized port on %s
\n
"
,
slave
->
dev
->
master
->
name
,
slave
->
dev
->
name
);
return
;
}
...
...
@@ -2021,7 +2027,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
dprintk
(
"Some port(s) related to LAG %d - replaceing with LAG %d
\n
"
,
aggregator
->
aggregator_identifier
,
new_aggregator
->
aggregator_identifier
);
if
((
new_aggregator
->
lag_ports
==
port
)
&&
new_aggregator
->
is_active
)
{
printk
(
KERN_INFO
DRV_NAME
": Removing an active aggregator
\n
"
);
printk
(
KERN_INFO
DRV_NAME
": %s: Removing an active aggregator
\n
"
,
aggregator
->
slave
->
dev
->
master
->
name
);
// select new active aggregator
select_new_active_agg
=
1
;
}
...
...
@@ -2051,15 +2058,17 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_agg_selection_logic
(
__get_first_agg
(
port
));
}
}
else
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: unbinding aggregator, "
"and could not find a new aggregator for its ports
\n
"
);
printk
(
KERN_WARNING
DRV_NAME
": %s: Warning: unbinding aggregator, "
"and could not find a new aggregator for its ports
\n
"
,
slave
->
dev
->
master
->
name
);
}
}
else
{
// in case that the only port related to this aggregator is the one we want to remove
select_new_active_agg
=
aggregator
->
is_active
;
// clear the aggregator
ad_clear_agg
(
aggregator
);
if
(
select_new_active_agg
)
{
printk
(
KERN_INFO
"Removing an active aggregator
\n
"
);
printk
(
KERN_INFO
DRV_NAME
": %s: Removing an active aggregator
\n
"
,
slave
->
dev
->
master
->
name
);
// select new active aggregator
ad_agg_selection_logic
(
__get_first_agg
(
port
));
}
...
...
@@ -2085,7 +2094,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
// clear the aggregator
ad_clear_agg
(
temp_aggregator
);
if
(
select_new_active_agg
)
{
printk
(
KERN_INFO
"Removing an active aggregator
\n
"
);
printk
(
KERN_INFO
DRV_NAME
": %s: Removing an active aggregator
\n
"
,
slave
->
dev
->
master
->
name
);
// select new active aggregator
ad_agg_selection_logic
(
__get_first_agg
(
port
));
}
...
...
@@ -2131,7 +2141,8 @@ void bond_3ad_state_machine_handler(struct bonding *bond)
// select the active aggregator for the bond
if
((
port
=
__get_first_port
(
bond
)))
{
if
(
!
port
->
slave
)
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: bond's first port is uninitialized
\n
"
);
printk
(
KERN_WARNING
DRV_NAME
": %s: Warning: bond's first port is "
"uninitialized
\n
"
,
bond
->
dev
->
name
);
goto
re_arm
;
}
...
...
@@ -2143,7 +2154,8 @@ void bond_3ad_state_machine_handler(struct bonding *bond)
// for each port run the state machines
for
(
port
=
__get_first_port
(
bond
);
port
;
port
=
__get_next_port
(
port
))
{
if
(
!
port
->
slave
)
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: Found an uninitialized port
\n
"
);
printk
(
KERN_WARNING
DRV_NAME
": %s: Warning: Found an uninitialized "
"port
\n
"
,
bond
->
dev
->
name
);
goto
re_arm
;
}
...
...
@@ -2184,7 +2196,8 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
port
=
&
(
SLAVE_AD_INFO
(
slave
).
port
);
if
(
!
port
->
slave
)
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: port of slave %s is uninitialized
\n
"
,
slave
->
dev
->
name
);
printk
(
KERN_WARNING
DRV_NAME
": %s: Warning: port of slave %s is "
"uninitialized
\n
"
,
slave
->
dev
->
name
,
slave
->
dev
->
master
->
name
);
return
;
}
...
...
@@ -2230,8 +2243,9 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
// if slave is null, the whole port is not initialized
if
(
!
port
->
slave
)
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: speed changed for uninitialized port on %s
\n
"
,
slave
->
dev
->
name
);
printk
(
KERN_WARNING
DRV_NAME
": Warning: %s: speed "
"changed for uninitialized port on %s
\n
"
,
slave
->
dev
->
master
->
name
,
slave
->
dev
->
name
);
return
;
}
...
...
@@ -2257,8 +2271,9 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
// if slave is null, the whole port is not initialized
if
(
!
port
->
slave
)
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: duplex changed for uninitialized port on %s
\n
"
,
slave
->
dev
->
name
);
printk
(
KERN_WARNING
DRV_NAME
": %s: Warning: duplex changed "
"for uninitialized port on %s
\n
"
,
slave
->
dev
->
master
->
name
,
slave
->
dev
->
name
);
return
;
}
...
...
@@ -2285,8 +2300,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
// if slave is null, the whole port is not initialized
if
(
!
port
->
slave
)
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: link status changed for uninitialized port on %s
\n
"
,
slave
->
dev
->
name
);
printk
(
KERN_WARNING
DRV_NAME
": Warning: %s: link status changed for "
"uninitialized port on %s
\n
"
,
slave
->
dev
->
master
->
name
,
slave
->
dev
->
name
);
return
;
}
...
...
@@ -2363,7 +2379,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
}
if
(
bond_3ad_get_active_agg_info
(
bond
,
&
ad_info
))
{
printk
(
KERN_DEBUG
"ERROR: bond_3ad_get_active_agg_info failed
\n
"
);
printk
(
KERN_DEBUG
DRV_NAME
": %s: Error: "
"bond_3ad_get_active_agg_info failed
\n
"
,
dev
->
name
);
goto
out
;
}
...
...
@@ -2372,7 +2389,9 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
if
(
slaves_in_agg
==
0
)
{
/*the aggregator is empty*/
printk
(
KERN_DEBUG
"ERROR: active aggregator is empty
\n
"
);
printk
(
KERN_DEBUG
DRV_NAME
": %s: Error: active "
"aggregator is empty
\n
"
,
dev
->
name
);
goto
out
;
}
...
...
@@ -2390,7 +2409,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
}
if
(
slave_agg_no
>=
0
)
{
printk
(
KERN_ERR
DRV_NAME
": Error: Couldn't find a slave to tx on for aggregator ID %d
\n
"
,
agg_id
);
printk
(
KERN_ERR
DRV_NAME
": %s: Error: Couldn't find a slave to tx on "
"for aggregator ID %d
\n
"
,
dev
->
name
,
agg_id
);
goto
out
;
}
...
...
drivers/net/bonding/bond_alb.c
View file @
83cbd33a
...
...
@@ -198,20 +198,21 @@ static int tlb_initialize(struct bonding *bond)
{
struct
alb_bond_info
*
bond_info
=
&
(
BOND_ALB_INFO
(
bond
));
int
size
=
TLB_HASH_TABLE_SIZE
*
sizeof
(
struct
tlb_client_info
);
struct
tlb_client_info
*
new_hashtbl
;
int
i
;
spin_lock_init
(
&
(
bond_info
->
tx_hashtbl_lock
));
_lock_tx_hashtbl
(
bond
);
bond_info
->
tx_hashtbl
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
!
bond_info
->
tx_hashtbl
)
{
new_hashtbl
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
!
new_hashtbl
)
{
printk
(
KERN_ERR
DRV_NAME
":
Error: %s
: Failed to allocate TLB hash table
\n
"
,
":
%s: Error
: Failed to allocate TLB hash table
\n
"
,
bond
->
dev
->
name
);
_unlock_tx_hashtbl
(
bond
);
return
-
1
;
}
_lock_tx_hashtbl
(
bond
);
bond_info
->
tx_hashtbl
=
new_hashtbl
;
memset
(
bond_info
->
tx_hashtbl
,
0
,
size
);
...
...
@@ -513,7 +514,8 @@ static void rlb_update_client(struct rlb_client_info *client_info)
client_info
->
mac_dst
);
if
(
!
skb
)
{
printk
(
KERN_ERR
DRV_NAME
": Error: failed to create an ARP packet
\n
"
);
": %s: Error: failed to create an ARP packet
\n
"
,
client_info
->
slave
->
dev
->
master
->
name
);
continue
;
}
...
...
@@ -523,7 +525,8 @@ static void rlb_update_client(struct rlb_client_info *client_info)
skb
=
vlan_put_tag
(
skb
,
client_info
->
vlan_id
);
if
(
!
skb
)
{
printk
(
KERN_ERR
DRV_NAME
": Error: failed to insert VLAN tag
\n
"
);
": %s: Error: failed to insert VLAN tag
\n
"
,
client_info
->
slave
->
dev
->
master
->
name
);
continue
;
}
}
...
...
@@ -606,8 +609,9 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip)
if
(
!
client_info
->
slave
)
{
printk
(
KERN_ERR
DRV_NAME
": Error: found a client with no channel in "
"the client's hash table
\n
"
);
": %s: Error: found a client with no channel in "
"the client's hash table
\n
"
,
bond
->
dev
->
name
);
continue
;
}
/*update all clients using this src_ip, that are not assigned
...
...
@@ -797,21 +801,22 @@ static int rlb_initialize(struct bonding *bond)
{
struct
alb_bond_info
*
bond_info
=
&
(
BOND_ALB_INFO
(
bond
));
struct
packet_type
*
pk_type
=
&
(
BOND_ALB_INFO
(
bond
).
rlb_pkt_type
);
struct
rlb_client_info
*
new_hashtbl
;
int
size
=
RLB_HASH_TABLE_SIZE
*
sizeof
(
struct
rlb_client_info
);
int
i
;
spin_lock_init
(
&
(
bond_info
->
rx_hashtbl_lock
));
_lock_rx_hashtbl
(
bond
);
bond_info
->
rx_hashtbl
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
!
bond_info
->
rx_hashtbl
)
{
new_hashtbl
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
!
new_hashtbl
)
{
printk
(
KERN_ERR
DRV_NAME
":
Error: %s
: Failed to allocate RLB hash table
\n
"
,
":
%s: Error
: Failed to allocate RLB hash table
\n
"
,
bond
->
dev
->
name
);
_unlock_rx_hashtbl
(
bond
);
return
-
1
;
}
_lock_rx_hashtbl
(
bond
);
bond_info
->
rx_hashtbl
=
new_hashtbl
;
bond_info
->
rx_hashtbl_head
=
RLB_NULL_INDEX
;
...
...
@@ -927,7 +932,8 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
skb
=
vlan_put_tag
(
skb
,
vlan
->
vlan_id
);
if
(
!
skb
)
{
printk
(
KERN_ERR
DRV_NAME
": Error: failed to insert VLAN tag
\n
"
);
": %s: Error: failed to insert VLAN tag
\n
"
,
bond
->
dev
->
name
);
continue
;
}
}
...
...
@@ -956,11 +962,11 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw)
s_addr
.
sa_family
=
dev
->
type
;
if
(
dev_set_mac_address
(
dev
,
&
s_addr
))
{
printk
(
KERN_ERR
DRV_NAME
": Error: dev_set_mac_address of dev %s failed! ALB "
":
%s:
Error: dev_set_mac_address of dev %s failed! ALB "
"mode requires that the base driver support setting "
"the hw address also when the network device's "
"interface is open
\n
"
,
dev
->
name
);
dev
->
master
->
name
,
dev
->
name
);
return
-
EOPNOTSUPP
;
}
return
0
;
...
...
@@ -1153,16 +1159,16 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
bond
->
alb_info
.
rlb_enabled
);
printk
(
KERN_WARNING
DRV_NAME
": Warning: the hw address of slave %s is in use by "
":
%s:
Warning: the hw address of slave %s is in use by "
"the bond; giving it the hw address of %s
\n
"
,
slave
->
dev
->
name
,
free_mac_slave
->
dev
->
name
);
bond
->
dev
->
name
,
slave
->
dev
->
name
,
free_mac_slave
->
dev
->
name
);
}
else
if
(
has_bond_addr
)
{
printk
(
KERN_ERR
DRV_NAME
": Error: the hw address of slave %s is in use by the "
":
%s:
Error: the hw address of slave %s is in use by the "
"bond; couldn't find a slave with a free hw address to "
"give it (this should not have happened)
\n
"
,
slave
->
dev
->
name
);
bond
->
dev
->
name
,
slave
->
dev
->
name
);
return
-
EFAULT
;
}
...
...
@@ -1250,6 +1256,8 @@ int bond_alb_initialize(struct bonding *bond, int rlb_enabled)
tlb_deinitialize
(
bond
);
return
res
;
}
}
else
{
bond
->
alb_info
.
rlb_enabled
=
0
;
}
return
0
;
...
...
@@ -1409,7 +1417,7 @@ void bond_alb_monitor(struct bonding *bond)
read_lock
(
&
bond
->
curr_slave_lock
);
bond_for_each_slave
(
bond
,
slave
,
i
)
{
alb_send_learning_packets
(
slave
,
slave
->
dev
->
dev_addr
);
alb_send_learning_packets
(
slave
,
slave
->
dev
->
dev_addr
);
}
read_unlock
(
&
bond
->
curr_slave_lock
);
...
...
drivers/net/bonding/bond_main.c
View file @
83cbd33a
...
...
@@ -489,6 +489,28 @@
* Set version to 2.6.3.
* 2005/09/26 - Jay Vosburgh <fubar@us.ibm.com>
* - Removed backwards compatibility for old ifenslaves. Version 2.6.4.
* 2005/09/27 - Mitch Williams <mitch.a.williams at intel dot com>
* - Radheka Godse <radheka.godse at intel dot com>
* - Split out bond creation code to allow for sysfs interface.
* - Removed static declaration on some functions and data items.
* - Added sysfs support, including capability to add/remove/change
* any bond at runtime.
*
* - Miscellaneous:
* - Added bonding: <bondname>: prefix to sysfs log messages
* - Added arp_ip_targets to /proc entry
* - Allow ARP target table to have empty entries
* - trivial fix: added missing modes description to modinfo
* - Corrected bug in ALB init where kmalloc is called inside
* a held lock
* - Corrected behavior to maintain bond link when changing
* from arp monitor to miimon and vice versa
* - Added missing bonding: <bondname>: prefix to alb, ad log messages
* - Fixed stack dump warnings seen if changing between miimon
* and arp monitoring when the bond interface is down.
* - Fixed stack dump warnings seen when enslaving an e100
* driver
* - Set version to 3.0.0
*/
//#define BONDING_DEBUG 1
...
...
@@ -557,6 +579,7 @@ static char *lacp_rate = NULL;
static
char
*
xmit_hash_policy
=
NULL
;
static
int
arp_interval
=
BOND_LINK_ARP_INTERV
;
static
char
*
arp_ip_target
[
BOND_MAX_ARP_TARGETS
]
=
{
NULL
,
};
struct
bond_params
bonding_defaults
;
module_param
(
max_bonds
,
int
,
0
);
MODULE_PARM_DESC
(
max_bonds
,
"Max number of bonded devices"
);
...
...
@@ -565,17 +588,24 @@ MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
module_param
(
updelay
,
int
,
0
);
MODULE_PARM_DESC
(
updelay
,
"Delay before considering link up, in milliseconds"
);
module_param
(
downdelay
,
int
,
0
);
MODULE_PARM_DESC
(
downdelay
,
"Delay before considering link down, in milliseconds"
);
MODULE_PARM_DESC
(
downdelay
,
"Delay before considering link down, "
"in milliseconds"
);
module_param
(
use_carrier
,
int
,
0
);
MODULE_PARM_DESC
(
use_carrier
,
"Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"
);
MODULE_PARM_DESC
(
use_carrier
,
"Use netif_carrier_ok (vs MII ioctls) in miimon; "
"0 for off, 1 for on (default)"
);
module_param
(
mode
,
charp
,
0
);
MODULE_PARM_DESC
(
mode
,
"Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"
);
MODULE_PARM_DESC
(
mode
,
"Mode of operation : 0 for balance-rr, "
"1 for active-backup, 2 for balance-xor, "
"3 for broadcast, 4 for 802.3ad, 5 for balance-tlb, "
"6 for balance-alb"
);
module_param
(
primary
,
charp
,
0
);
MODULE_PARM_DESC
(
primary
,
"Primary network device to use"
);
module_param
(
lacp_rate
,
charp
,
0
);
MODULE_PARM_DESC
(
lacp_rate
,
"LACPDU tx rate to request from 802.3ad partner (slow/fast)"
);
MODULE_PARM_DESC
(
lacp_rate
,
"LACPDU tx rate to request from 802.3ad partner "
"(slow/fast)"
);
module_param
(
xmit_hash_policy
,
charp
,
0
);
MODULE_PARM_DESC
(
xmit_hash_policy
,
"XOR hashing method : 0 for layer 2 (default), 1 for layer 3+4"
);
MODULE_PARM_DESC
(
xmit_hash_policy
,
"XOR hashing method: 0 for layer 2 (default)"
", 1 for layer 3+4"
);
module_param
(
arp_interval
,
int
,
0
);
MODULE_PARM_DESC
(
arp_interval
,
"arp interval in milliseconds"
);
module_param_array
(
arp_ip_target
,
charp
,
NULL
,
0
);
...
...
@@ -586,30 +616,27 @@ MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
static
const
char
*
version
=
DRV_DESCRIPTION
": v"
DRV_VERSION
" ("
DRV_RELDATE
")
\n
"
;
static
LIST_HEAD
(
bond_dev_list
);
LIST_HEAD
(
bond_dev_list
);
#ifdef CONFIG_PROC_FS
static
struct
proc_dir_entry
*
bond_proc_dir
=
NULL
;
#endif
extern
struct
rw_semaphore
bonding_rwsem
;
static
u32
arp_target
[
BOND_MAX_ARP_TARGETS
]
=
{
0
,
}
;
static
int
arp_ip_count
=
0
;
static
int
bond_mode
=
BOND_MODE_ROUNDROBIN
;
static
int
xmit_hashtype
=
BOND_XMIT_POLICY_LAYER2
;
static
int
lacp_fast
=
0
;
struct
bond_parm_tbl
{
char
*
modename
;
int
mode
;
};
st
atic
st
ruct
bond_parm_tbl
bond_lacp_tbl
[]
=
{
struct
bond_parm_tbl
bond_lacp_tbl
[]
=
{
{
"slow"
,
AD_LACP_SLOW
},
{
"fast"
,
AD_LACP_FAST
},
{
NULL
,
-
1
},
};
st
atic
st
ruct
bond_parm_tbl
bond_mode_tbl
[]
=
{
struct
bond_parm_tbl
bond_mode_tbl
[]
=
{
{
"balance-rr"
,
BOND_MODE_ROUNDROBIN
},
{
"active-backup"
,
BOND_MODE_ACTIVEBACKUP
},
{
"balance-xor"
,
BOND_MODE_XOR
},
...
...
@@ -620,7 +647,7 @@ static struct bond_parm_tbl bond_mode_tbl[] = {
{
NULL
,
-
1
},
};
st
atic
st
ruct
bond_parm_tbl
xmit_hashtype_tbl
[]
=
{
struct
bond_parm_tbl
xmit_hashtype_tbl
[]
=
{
{
"layer2"
,
BOND_XMIT_POLICY_LAYER2
},
{
"layer3+4"
,
BOND_XMIT_POLICY_LAYER34
},
{
NULL
,
-
1
},
...
...
@@ -628,12 +655,11 @@ static struct bond_parm_tbl xmit_hashtype_tbl[] = {
/*-------------------------- Forward declarations ---------------------------*/
static
inline
void
bond_set_mode_ops
(
struct
bonding
*
bond
,
int
mode
);
static
void
bond_send_gratuitous_arp
(
struct
bonding
*
bond
);
/*---------------------------- General routines -----------------------------*/
static
const
char
*
bond_mode_name
(
int
mode
)
const
char
*
bond_mode_name
(
int
mode
)
{
switch
(
mode
)
{
case
BOND_MODE_ROUNDROBIN
:
...
...
@@ -910,7 +936,7 @@ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid)
res
=
bond_add_vlan
(
bond
,
vid
);
if
(
res
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Failed to add vlan id %d
\n
"
,
": %s:
Error:
Failed to add vlan id %d
\n
"
,
bond_dev
->
name
,
vid
);
}
}
...
...
@@ -944,7 +970,7 @@ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)
res
=
bond_del_vlan
(
bond
,
vid
);
if
(
res
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Failed to remove vlan id %d
\n
"
,
": %s:
Error:
Failed to remove vlan id %d
\n
"
,
bond_dev
->
name
,
vid
);
}
}
...
...
@@ -1449,7 +1475,7 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
*
* Warning: Caller must hold curr_slave_lock for writing.
*/
static
void
bond_change_active_slave
(
struct
bonding
*
bond
,
struct
slave
*
new_active
)
void
bond_change_active_slave
(
struct
bonding
*
bond
,
struct
slave
*
new_active
)
{
struct
slave
*
old_active
=
bond
->
curr_active_slave
;
...
...
@@ -1523,7 +1549,7 @@ static void bond_change_active_slave(struct bonding *bond, struct slave *new_act
*
* Warning: Caller must hold curr_slave_lock for writing.
*/
static
void
bond_select_active_slave
(
struct
bonding
*
bond
)
void
bond_select_active_slave
(
struct
bonding
*
bond
)
{
struct
slave
*
best_slave
;
...
...
@@ -1591,7 +1617,7 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave)
/*---------------------------------- IOCTL ----------------------------------*/
static
int
bond_sethwaddr
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
)
int
bond_sethwaddr
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
)
{
dprintk
(
"bond_dev=%p
\n
"
,
bond_dev
);
dprintk
(
"slave_dev=%p
\n
"
,
slave_dev
);
...
...
@@ -1631,7 +1657,7 @@ static int bond_compute_features(struct bonding *bond)
}
/* enslave device <slave> to bond device <master> */
static
int
bond_enslave
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
)
int
bond_enslave
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
)
{
struct
bonding
*
bond
=
bond_dev
->
priv
;
struct
slave
*
new_slave
=
NULL
;
...
...
@@ -1644,8 +1670,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
if
(
!
bond
->
params
.
use_carrier
&&
slave_dev
->
ethtool_ops
==
NULL
&&
slave_dev
->
do_ioctl
==
NULL
)
{
printk
(
KERN_WARNING
DRV_NAME
":
Warning
: no link monitoring support for %s
\n
"
,
slave_dev
->
name
);
":
%s: Warning
: no link monitoring support for %s
\n
"
,
bond_dev
->
name
,
slave_dev
->
name
);
}
/* bond must be initialized by bond_open() before enslaving */
...
...
@@ -1666,17 +1692,17 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
dprintk
(
"%s: NETIF_F_VLAN_CHALLENGED
\n
"
,
slave_dev
->
name
);
if
(
!
list_empty
(
&
bond
->
vlan_list
))
{
printk
(
KERN_ERR
DRV_NAME
": Error: cannot enslave VLAN "
":
%s:
Error: cannot enslave VLAN "
"challenged slave %s on VLAN enabled "
"bond %s
\n
"
,
slave_dev
->
name
,
"bond %s
\n
"
,
bond_dev
->
name
,
slave_dev
->
name
,
bond_dev
->
name
);
return
-
EPERM
;
}
else
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: enslaved VLAN challenged "
":
%s:
Warning: enslaved VLAN challenged "
"slave %s. Adding VLANs will be blocked as "
"long as %s is part of bond %s
\n
"
,
slave_dev
->
name
,
slave_dev
->
name
,
bond_dev
->
name
,
slave_dev
->
name
,
slave_dev
->
name
,
bond_dev
->
name
);
bond_dev
->
features
|=
NETIF_F_VLAN_CHALLENGED
;
}
...
...
@@ -1706,12 +1732,11 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
if
(
slave_dev
->
set_mac_address
==
NULL
)
{
printk
(
KERN_ERR
DRV_NAME
": Error: The slave device you specified does "
"not support setting the MAC address.
\n
"
);
printk
(
KERN_ERR
"Your kernel likely does not support slave devices.
\n
"
);
res
=
-
EOPNOTSUPP
;
": %s: Error: The slave device you specified does "
"not support setting the MAC address. "
"Your kernel likely does not support slave "
"devices.
\n
"
,
bond_dev
->
name
);
res
=
-
EOPNOTSUPP
;
goto
err_undo_flags
;
}
...
...
@@ -1827,21 +1852,21 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
* the messages for netif_carrier.
*/
printk
(
KERN_WARNING
DRV_NAME
": Warning: MII and ETHTOOL support not "
":
%s:
Warning: MII and ETHTOOL support not "
"available for interface %s, and "
"arp_interval/arp_ip_target module parameters "
"not specified, thus bonding will not detect "
"link failures! see bonding.txt for details.
\n
"
,
slave_dev
->
name
);
bond_dev
->
name
,
slave_dev
->
name
);
}
else
if
(
link_reporting
==
-
1
)
{
/* unable get link status using mii/ethtool */
printk
(
KERN_WARNING
DRV_NAME
": Warning: can't get link status from "
":
%s:
Warning: can't get link status from "
"interface %s; the network driver associated "
"with this interface does not support MII or "
"ETHTOOL link status reporting, thus miimon "
"has no effect on this interface.
\n
"
,
slave_dev
->
name
);
bond_dev
->
name
,
slave_dev
->
name
);
}
}
...
...
@@ -1868,15 +1893,15 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
if
(
bond_update_speed_duplex
(
new_slave
)
&&
(
new_slave
->
link
!=
BOND_LINK_DOWN
))
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: failed to get speed and duplex from %s, "
":
%s:
Warning: failed to get speed and duplex from %s, "
"assumed to be 100Mb/sec and Full.
\n
"
,
new_slave
->
dev
->
name
);
bond_dev
->
name
,
new_slave
->
dev
->
name
);
if
(
bond
->
params
.
mode
==
BOND_MODE_8023AD
)
{
printk
(
KERN_WARNING
"Operation of 802.3ad mode requires ETHTOOL "
printk
(
KERN_WARNING
DRV_NAME
"
: %s: Warning:
Operation of 802.3ad mode requires ETHTOOL "
"support in base driver for proper aggregator "
"selection.
\n
"
);
"selection.
\n
"
,
bond_dev
->
name
);
}
}
...
...
@@ -1958,6 +1983,10 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
write_unlock_bh
(
&
bond
->
lock
);
res
=
bond_create_slave_symlinks
(
bond_dev
,
slave_dev
);
if
(
res
)
goto
err_unset_master
;
printk
(
KERN_INFO
DRV_NAME
": %s: enslaving %s as a%s interface with a%s link.
\n
"
,
bond_dev
->
name
,
slave_dev
->
name
,
...
...
@@ -1999,7 +2028,7 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
* for Bonded connections:
* The first up interface should be left on and all others downed.
*/
static
int
bond_release
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
)
int
bond_release
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
)
{
struct
bonding
*
bond
=
bond_dev
->
priv
;
struct
slave
*
slave
,
*
oldcurrent
;
...
...
@@ -2010,7 +2039,7 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
if
(
!
(
slave_dev
->
flags
&
IFF_SLAVE
)
||
(
slave_dev
->
master
!=
bond_dev
))
{
printk
(
KERN_ERR
DRV_NAME
":
Error: %s
: cannot release %s.
\n
"
,
":
%s: Error
: cannot release %s.
\n
"
,
bond_dev
->
name
,
slave_dev
->
name
);
return
-
EINVAL
;
}
...
...
@@ -2031,11 +2060,12 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
ETH_ALEN
);
if
(
!
mac_addr_differ
&&
(
bond
->
slave_cnt
>
1
))
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: the permanent HWaddr of %s "
":
%s:
Warning: the permanent HWaddr of %s "
"- %02X:%02X:%02X:%02X:%02X:%02X - is "
"still in use by %s. Set the HWaddr of "
"%s to a different address to avoid "
"conflicts.
\n
"
,
bond_dev
->
name
,
slave_dev
->
name
,
slave
->
perm_hwaddr
[
0
],
slave
->
perm_hwaddr
[
1
],
...
...
@@ -2111,24 +2141,28 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
bond_dev
->
features
|=
NETIF_F_VLAN_CHALLENGED
;
}
else
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: clearing HW address of %s while it "
":
%s:
Warning: clearing HW address of %s while it "
"still has VLANs.
\n
"
,
bond_dev
->
name
);
bond_dev
->
name
,
bond_dev
->
name
);
printk
(
KERN_WARNING
DRV_NAME
": When re-adding slaves, make sure the bond's "
"HW address matches its VLANs'.
\n
"
);
": %s: When re-adding slaves, make sure the bond's "
"HW address matches its VLANs'.
\n
"
,
bond_dev
->
name
);
}
}
else
if
((
bond_dev
->
features
&
NETIF_F_VLAN_CHALLENGED
)
&&
!
bond_has_challenged_slaves
(
bond
))
{
printk
(
KERN_INFO
DRV_NAME
": last VLAN challenged slave %s "
":
%s:
last VLAN challenged slave %s "
"left bond %s. VLAN blocking is removed
\n
"
,
slave_dev
->
name
,
bond_dev
->
name
);
bond_dev
->
name
,
slave_dev
->
name
,
bond_dev
->
name
);
bond_dev
->
features
&=
~
NETIF_F_VLAN_CHALLENGED
;
}
write_unlock_bh
(
&
bond
->
lock
);
/* must do this from outside any spinlocks */
bond_destroy_slave_symlinks
(
bond_dev
,
slave_dev
);
bond_del_vlans_from_slave
(
bond
,
slave_dev
);
/* If the mode USES_PRIMARY, then we should only remove its
...
...
@@ -2220,6 +2254,7 @@ static int bond_release_all(struct net_device *bond_dev)
*/
write_unlock_bh
(
&
bond
->
lock
);
bond_destroy_slave_symlinks
(
bond_dev
,
slave_dev
);
bond_del_vlans_from_slave
(
bond
,
slave_dev
);
/* If the mode USES_PRIMARY, then we should only remove its
...
...
@@ -2274,12 +2309,13 @@ static int bond_release_all(struct net_device *bond_dev)
bond_dev
->
features
|=
NETIF_F_VLAN_CHALLENGED
;
}
else
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: clearing HW address of %s while it "
":
%s:
Warning: clearing HW address of %s while it "
"still has VLANs.
\n
"
,
bond_dev
->
name
);
bond_dev
->
name
,
bond_dev
->
name
);
printk
(
KERN_WARNING
DRV_NAME
": When re-adding slaves, make sure the bond's "
"HW address matches its VLANs'.
\n
"
);
": %s: When re-adding slaves, make sure the bond's "
"HW address matches its VLANs'.
\n
"
,
bond_dev
->
name
);
}
printk
(
KERN_INFO
DRV_NAME
...
...
@@ -2397,7 +2433,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
/*-------------------------------- Monitoring -------------------------------*/
/* this function is called regularly to monitor each slave's link. */
static
void
bond_mii_monitor
(
struct
net_device
*
bond_dev
)
void
bond_mii_monitor
(
struct
net_device
*
bond_dev
)
{
struct
bonding
*
bond
=
bond_dev
->
priv
;
struct
slave
*
slave
,
*
oldcurrent
;
...
...
@@ -2596,8 +2632,11 @@ static void bond_mii_monitor(struct net_device *bond_dev)
break
;
default:
/* Should not happen */
printk
(
KERN_ERR
"bonding: Error: %s Illegal value (link=%d)
\n
"
,
slave
->
dev
->
name
,
slave
->
link
);
printk
(
KERN_ERR
DRV_NAME
": %s: Error: %s Illegal value (link=%d)
\n
"
,
bond_dev
->
name
,
slave
->
dev
->
name
,
slave
->
link
);
goto
out
;
}
/* end of switch (slave->link) */
...
...
@@ -2721,7 +2760,9 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
struct
flowi
fl
;
struct
rtable
*
rt
;
for
(
i
=
0
;
(
i
<
BOND_MAX_ARP_TARGETS
)
&&
targets
[
i
];
i
++
)
{
for
(
i
=
0
;
(
i
<
BOND_MAX_ARP_TARGETS
);
i
++
)
{
if
(
!
targets
[
i
])
continue
;
dprintk
(
"basa: target %x
\n
"
,
targets
[
i
]);
if
(
list_empty
(
&
bond
->
vlan_list
))
{
dprintk
(
"basa: empty vlan: arp_send
\n
"
);
...
...
@@ -2825,7 +2866,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
* arp is transmitted to generate traffic. see activebackup_arp_monitor for
* arp monitoring in active backup mode.
*/
static
void
bond_loadbalance_arp_mon
(
struct
net_device
*
bond_dev
)
void
bond_loadbalance_arp_mon
(
struct
net_device
*
bond_dev
)
{
struct
bonding
*
bond
=
bond_dev
->
priv
;
struct
slave
*
slave
,
*
oldcurrent
;
...
...
@@ -2963,7 +3004,7 @@ static void bond_loadbalance_arp_mon(struct net_device *bond_dev)
* may have received.
* see loadbalance_arp_monitor for arp monitoring in load balancing mode
*/
static
void
bond_activebackup_arp_mon
(
struct
net_device
*
bond_dev
)
void
bond_activebackup_arp_mon
(
struct
net_device
*
bond_dev
)
{
struct
bonding
*
bond
=
bond_dev
->
priv
;
struct
slave
*
slave
;
...
...
@@ -3249,6 +3290,8 @@ static void bond_info_show_master(struct seq_file *seq)
{
struct
bonding
*
bond
=
seq
->
private
;
struct
slave
*
curr
;
int
i
;
u32
target
;
read_lock
(
&
bond
->
curr_slave_lock
);
curr
=
bond
->
curr_active_slave
;
...
...
@@ -3257,10 +3300,17 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf
(
seq
,
"Bonding Mode: %s
\n
"
,
bond_mode_name
(
bond
->
params
.
mode
));
if
(
bond
->
params
.
mode
==
BOND_MODE_XOR
||
bond
->
params
.
mode
==
BOND_MODE_8023AD
)
{
seq_printf
(
seq
,
"Transmit Hash Policy: %s (%d)
\n
"
,
xmit_hashtype_tbl
[
bond
->
params
.
xmit_policy
].
modename
,
bond
->
params
.
xmit_policy
);
}
if
(
USES_PRIMARY
(
bond
->
params
.
mode
))
{
seq_printf
(
seq
,
"Primary Slave: %s
\n
"
,
(
bond
->
p
arams
.
primary
[
0
]
)
?
bond
->
params
.
primary
:
"None"
);
(
bond
->
p
rimary_slave
)
?
bond
->
primary_slave
->
dev
->
name
:
"None"
);
seq_printf
(
seq
,
"Currently Active Slave: %s
\n
"
,
(
curr
)
?
curr
->
dev
->
name
:
"None"
);
...
...
@@ -3273,6 +3323,27 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf
(
seq
,
"Down Delay (ms): %d
\n
"
,
bond
->
params
.
downdelay
*
bond
->
params
.
miimon
);
/* ARP information */
if
(
bond
->
params
.
arp_interval
>
0
)
{
int
printed
=
0
;
seq_printf
(
seq
,
"ARP Polling Interval (ms): %d
\n
"
,
bond
->
params
.
arp_interval
);
seq_printf
(
seq
,
"ARP IP target/s (n.n.n.n form):"
);
for
(
i
=
0
;
(
i
<
BOND_MAX_ARP_TARGETS
)
;
i
++
)
{
if
(
!
bond
->
params
.
arp_targets
[
i
])
continue
;
if
(
printed
)
seq_printf
(
seq
,
","
);
target
=
ntohl
(
bond
->
params
.
arp_targets
[
i
]);
seq_printf
(
seq
,
" %d.%d.%d.%d"
,
HIPQUAD
(
target
));
printed
=
1
;
}
seq_printf
(
seq
,
"
\n
"
);
}
if
(
bond
->
params
.
mode
==
BOND_MODE_8023AD
)
{
struct
ad_info
ad_info
;
...
...
@@ -3478,7 +3549,10 @@ static int bond_event_changename(struct bonding *bond)
bond_remove_proc_entry
(
bond
);
bond_create_proc_entry
(
bond
);
#endif
down_write
(
&
(
bonding_rwsem
));
bond_destroy_sysfs_entry
(
bond
);
bond_create_sysfs_entry
(
bond
);
up_write
(
&
(
bonding_rwsem
));
return
NOTIFY_DONE
;
}
...
...
@@ -3955,6 +4029,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
return
-
EPERM
;
}
down_write
(
&
(
bonding_rwsem
));
slave_dev
=
dev_get_by_name
(
ifr
->
ifr_slave
);
dprintk
(
"slave_dev=%p:
\n
"
,
slave_dev
);
...
...
@@ -3987,6 +4062,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
dev_put
(
slave_dev
);
}
up_write
(
&
(
bonding_rwsem
));
return
res
;
}
...
...
@@ -4071,6 +4147,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
bond_for_each_slave
(
bond
,
slave
,
i
)
{
dprintk
(
"s %p s->p %p c_m %p
\n
"
,
slave
,
slave
->
prev
,
slave
->
dev
->
change_mtu
);
res
=
dev_set_mtu
(
slave
->
dev
,
new_mtu
);
if
(
res
)
{
...
...
@@ -4397,8 +4474,9 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
struct
sk_buff
*
skb2
=
skb_clone
(
skb
,
GFP_ATOMIC
);
if
(
!
skb2
)
{
printk
(
KERN_ERR
DRV_NAME
": Error: bond_xmit_broadcast(): "
"skb_clone() failed
\n
"
);
": %s: Error: bond_xmit_broadcast(): "
"skb_clone() failed
\n
"
,
bond_dev
->
name
);
continue
;
}
...
...
@@ -4431,7 +4509,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
/*
* set bond mode specific net device operations
*/
static
inline
void
bond_set_mode_ops
(
struct
bonding
*
bond
,
int
mode
)
void
bond_set_mode_ops
(
struct
bonding
*
bond
,
int
mode
)
{
struct
net_device
*
bond_dev
=
bond
->
dev
;
...
...
@@ -4467,7 +4545,8 @@ static inline void bond_set_mode_ops(struct bonding *bond, int mode)
default:
/* Should never happen, mode already checked */
printk
(
KERN_ERR
DRV_NAME
": Error: Unknown bonding mode %d
\n
"
,
": %s: Error: Unknown bonding mode %d
\n
"
,
bond_dev
->
name
,
mode
);
break
;
}
...
...
@@ -4491,7 +4570,7 @@ static struct ethtool_ops bond_ethtool_ops = {
* Does not allocate but creates a /proc entry.
* Allowed to fail.
*/
static
int
__init
bond_init
(
struct
net_device
*
bond_dev
,
struct
bond_params
*
params
)
static
int
bond_init
(
struct
net_device
*
bond_dev
,
struct
bond_params
*
params
)
{
struct
bonding
*
bond
=
bond_dev
->
priv
;
...
...
@@ -4565,7 +4644,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
/* De-initialize device specific data.
* Caller must hold rtnl_lock.
*/
static
inline
void
bond_deinit
(
struct
net_device
*
bond_dev
)
void
bond_deinit
(
struct
net_device
*
bond_dev
)
{
struct
bonding
*
bond
=
bond_dev
->
priv
;
...
...
@@ -4601,7 +4680,7 @@ static void bond_free_all(void)
* Convert string input module parms. Accept either the
* number of the mode or its string name.
*/
static
inline
int
bond_parse_parm
(
char
*
mode_arg
,
struct
bond_parm_tbl
*
tbl
)
int
bond_parse_parm
(
char
*
mode_arg
,
struct
bond_parm_tbl
*
tbl
)
{
int
i
;
...
...
@@ -4670,7 +4749,7 @@ static int bond_check_params(struct bond_params *params)
if
(
max_bonds
<
1
||
max_bonds
>
INT_MAX
)
{
printk
(
KERN_WARNING
DRV_NAME
": Warning: max_bonds (%d) not in range %d-%d, so it "
"was reset to BOND_DEFAULT_MAX_BONDS (%d)"
,
"was reset to BOND_DEFAULT_MAX_BONDS (%d)
\n
"
,
max_bonds
,
1
,
INT_MAX
,
BOND_DEFAULT_MAX_BONDS
);
max_bonds
=
BOND_DEFAULT_MAX_BONDS
;
}
...
...
@@ -4881,81 +4960,96 @@ static int bond_check_params(struct bond_params *params)
return
0
;
}
/* Create a new bond based on the specified name and bonding parameters.
* Caller must NOT hold rtnl_lock; we need to release it here before we
* set up our sysfs entries.
*/
int
bond_create
(
char
*
name
,
struct
bond_params
*
params
,
struct
bonding
**
newbond
)
{
struct
net_device
*
bond_dev
;
int
res
;
rtnl_lock
();
bond_dev
=
alloc_netdev
(
sizeof
(
struct
bonding
),
name
,
ether_setup
);
if
(
!
bond_dev
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: eek! can't alloc netdev!
\n
"
,
name
);
res
=
-
ENOMEM
;
goto
out_rtnl
;
}
/* bond_init() must be called after dev_alloc_name() (for the
* /proc files), but before register_netdevice(), because we
* need to set function pointers.
*/
res
=
bond_init
(
bond_dev
,
params
);
if
(
res
<
0
)
{
goto
out_netdev
;
}
SET_MODULE_OWNER
(
bond_dev
);
res
=
register_netdevice
(
bond_dev
);
if
(
res
<
0
)
{
goto
out_bond
;
}
if
(
newbond
)
*
newbond
=
bond_dev
->
priv
;
rtnl_unlock
();
/* allows sysfs registration of net device */
res
=
bond_create_sysfs_entry
(
bond_dev
->
priv
);
goto
done
;
out_bond:
bond_deinit
(
bond_dev
);
out_netdev:
free_netdev
(
bond_dev
);
out_rtnl:
rtnl_unlock
();
done:
return
res
;
}
static
int
__init
bonding_init
(
void
)
{
struct
bond_params
params
;
int
i
;
int
res
;
char
new_bond_name
[
8
];
/* Enough room for 999 bonds at init. */
printk
(
KERN_INFO
"%s"
,
version
);
res
=
bond_check_params
(
&
param
s
);
res
=
bond_check_params
(
&
bonding_default
s
);
if
(
res
)
{
return
res
;
goto
out
;
}
rtnl_lock
();
#ifdef CONFIG_PROC_FS
bond_create_proc_dir
();
#endif
for
(
i
=
0
;
i
<
max_bonds
;
i
++
)
{
struct
net_device
*
bond_dev
;
bond_dev
=
alloc_netdev
(
sizeof
(
struct
bonding
),
""
,
ether_setup
);
if
(
!
bond_dev
)
{
res
=
-
ENOMEM
;
goto
out_err
;
}
res
=
dev_alloc_name
(
bond_dev
,
"bond%d"
);
if
(
res
<
0
)
{
free_netdev
(
bond_dev
);
goto
out_err
;
}
/* bond_init() must be called after dev_alloc_name() (for the
* /proc files), but before register_netdevice(), because we
* need to set function pointers.
*/
res
=
bond_init
(
bond_dev
,
&
params
);
if
(
res
<
0
)
{
free_netdev
(
bond_dev
);
goto
out_err
;
}
SET_MODULE_OWNER
(
bond_dev
);
res
=
register_netdevice
(
bond_dev
);
if
(
res
<
0
)
{
bond_deinit
(
bond_dev
);
free_netdev
(
bond_dev
);
goto
out_err
;
}
sprintf
(
new_bond_name
,
"bond%d"
,
i
);
res
=
bond_create
(
new_bond_name
,
&
bonding_defaults
,
NULL
);
if
(
res
)
goto
err
;
}
rtnl_unlock
();
res
=
bond_create_sysfs
();
if
(
res
)
goto
err
;
register_netdevice_notifier
(
&
bond_netdev_notifier
);
register_inetaddr_notifier
(
&
bond_inetaddr_notifier
);
return
0
;
out_err:
/*
* rtnl_unlock() will run netdev_run_todo(), putting the
* thus-far-registered bonding devices into a state which
* unregigister_netdevice() will accept
*/
rtnl_unlock
();
goto
out
;
err:
rtnl_lock
();
/* free and unregister all bonds that were successfully added */
bond_free_all
();
bond_destroy_sysfs
();
rtnl_unlock
();
out:
return
res
;
}
static
void
__exit
bonding_exit
(
void
)
...
...
@@ -4965,6 +5059,7 @@ static void __exit bonding_exit(void)
rtnl_lock
();
bond_free_all
();
bond_destroy_sysfs
();
rtnl_unlock
();
}
...
...
drivers/net/bonding/bond_sysfs.c
0 → 100644
View file @
83cbd33a
/*
* Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*
* Changes:
*
* 2004/12/12 - Mitch Williams <mitch.a.williams at intel dot com>
* - Initial creation of sysfs interface.
*
* 2005/06/22 - Radheka Godse <radheka.godse at intel dot com>
* - Added ifenslave -c type functionality to sysfs
* - Added sysfs files for attributes such as MII Status and
* 802.3ad aggregator that are displayed in /proc
* - Added "name value" format to sysfs "mode" and
* "lacp_rate", for e.g., "active-backup 1" or "slow 0" for
* consistency and ease of script parsing
* - Fixed reversal of octets in arp_ip_targets via sysfs
* - sysfs support to handle bond interface re-naming
* - Moved all sysfs entries into /sys/class/net instead of
* of using a standalone subsystem.
* - Added sysfs symlinks between masters and slaves
* - Corrected bugs in sysfs unload path when creating bonds
* with existing interface names.
* - Removed redundant sysfs stat file since it duplicates slave info
* from the proc file
* - Fixed errors in sysfs show/store arp targets.
* - For consistency with ifenslave, instead of exiting
* with an error, updated bonding sysfs to
* close and attempt to enslave an up adapter.
* - Fixed NULL dereference when adding a slave interface
* that does not exist.
* - Added checks in sysfs bonding to reject invalid ip addresses
* - Synch up with post linux-2.6.12 bonding changes
* - Created sysfs bond attrib for xmit_hash_policy
*
* 2005/09/19 - Mitch Williams <mitch.a.williams at intel dot com>
* - Changed semantics of multi-item files to be command-based
* instead of list-based.
* - Changed ARP target handler to use in_aton instead of sscanf
* - Style changes.
* 2005/09/27 - Mitch Williams <mitch.a.williams at intel dot com>
* - Made line endings consistent.
* - Removed "none" from primary output - just put blank instead
* - Fixed bug with long interface names
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/in.h>
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/rtnetlink.h>
/* #define BONDING_DEBUG 1 */
#include "bonding.h"
#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
#define to_net_dev(class) container_of(class, struct net_device, class_dev)
#define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv))
/*---------------------------- Declarations -------------------------------*/
extern
struct
list_head
bond_dev_list
;
extern
struct
bond_params
bonding_defaults
;
extern
struct
bond_parm_tbl
bond_mode_tbl
[];
extern
struct
bond_parm_tbl
bond_lacp_tbl
[];
extern
struct
bond_parm_tbl
xmit_hashtype_tbl
[];
static
int
expected_refcount
=
-
1
;
static
struct
class
*
netdev_class
;
/*--------------------------- Data Structures -----------------------------*/
/* Bonding sysfs lock. Why can't we just use the subsytem lock?
* Because kobject_register tries to acquire the subsystem lock. If
* we already hold the lock (which we would if the user was creating
* a new bond through the sysfs interface), we deadlock.
* This lock is only needed when deleting a bond - we need to make sure
* that we don't collide with an ongoing ioctl.
*/
struct
rw_semaphore
bonding_rwsem
;
/*------------------------------ Functions --------------------------------*/
/*
* "show" function for the bond_masters attribute.
* The class parameter is ignored.
*/
static
ssize_t
bonding_show_bonds
(
struct
class
*
cls
,
char
*
buffer
)
{
int
res
=
0
;
struct
bonding
*
bond
;
down_read
(
&
(
bonding_rwsem
));
list_for_each_entry
(
bond
,
&
bond_dev_list
,
bond_list
)
{
if
(
res
>
(
PAGE_SIZE
-
IFNAMSIZ
))
{
/* not enough space for another interface name */
if
((
PAGE_SIZE
-
res
)
>
10
)
res
=
PAGE_SIZE
-
10
;
res
+=
sprintf
(
buffer
+
res
,
"++more++"
);
break
;
}
res
+=
sprintf
(
buffer
+
res
,
"%s "
,
bond
->
dev
->
name
);
}
res
+=
sprintf
(
buffer
+
res
,
"
\n
"
);
res
++
;
up_read
(
&
(
bonding_rwsem
));
return
res
;
}
/*
* "store" function for the bond_masters attribute. This is what
* creates and deletes entire bonds.
*
* The class parameter is ignored.
*
*/
static
ssize_t
bonding_store_bonds
(
struct
class
*
cls
,
const
char
*
buffer
,
size_t
count
)
{
char
command
[
IFNAMSIZ
+
1
]
=
{
0
,
};
char
*
ifname
;
int
res
=
count
;
struct
bonding
*
bond
;
struct
bonding
*
nxt
;
down_write
(
&
(
bonding_rwsem
));
sscanf
(
buffer
,
"%16s"
,
command
);
/* IFNAMSIZ*/
ifname
=
command
+
1
;
if
((
strlen
(
command
)
<=
1
)
||
!
dev_valid_name
(
ifname
))
goto
err_no_cmd
;
if
(
command
[
0
]
==
'+'
)
{
/* Check to see if the bond already exists. */
list_for_each_entry_safe
(
bond
,
nxt
,
&
bond_dev_list
,
bond_list
)
if
(
strnicmp
(
bond
->
dev
->
name
,
ifname
,
IFNAMSIZ
)
==
0
)
{
printk
(
KERN_ERR
DRV_NAME
": cannot add bond %s; it already exists
\n
"
,
ifname
);
res
=
-
EPERM
;
goto
out
;
}
printk
(
KERN_INFO
DRV_NAME
": %s is being created...
\n
"
,
ifname
);
if
(
bond_create
(
ifname
,
&
bonding_defaults
,
&
bond
))
{
printk
(
KERN_INFO
DRV_NAME
": %s interface already exists. Bond creation failed.
\n
"
,
ifname
);
res
=
-
EPERM
;
}
goto
out
;
}
if
(
command
[
0
]
==
'-'
)
{
list_for_each_entry_safe
(
bond
,
nxt
,
&
bond_dev_list
,
bond_list
)
if
(
strnicmp
(
bond
->
dev
->
name
,
ifname
,
IFNAMSIZ
)
==
0
)
{
rtnl_lock
();
/* check the ref count on the bond's kobject.
* If it's > expected, then there's a file open,
* and we have to fail.
*/
if
(
atomic_read
(
&
bond
->
dev
->
class_dev
.
kobj
.
kref
.
refcount
)
>
expected_refcount
){
rtnl_unlock
();
printk
(
KERN_INFO
DRV_NAME
": Unable remove bond %s due to open references.
\n
"
,
ifname
);
res
=
-
EPERM
;
goto
out
;
}
printk
(
KERN_INFO
DRV_NAME
": %s is being deleted...
\n
"
,
bond
->
dev
->
name
);
unregister_netdevice
(
bond
->
dev
);
bond_deinit
(
bond
->
dev
);
bond_destroy_sysfs_entry
(
bond
);
rtnl_unlock
();
goto
out
;
}
printk
(
KERN_ERR
DRV_NAME
": unable to delete non-existent bond %s
\n
"
,
ifname
);
res
=
-
ENODEV
;
goto
out
;
}
err_no_cmd:
printk
(
KERN_ERR
DRV_NAME
": no command found in bonding_masters. Use +ifname or -ifname.
\n
"
);
res
=
-
EPERM
;
/* Always return either count or an error. If you return 0, you'll
* get called forever, which is bad.
*/
out:
up_write
(
&
(
bonding_rwsem
));
return
res
;
}
/* class attribute for bond_masters file. This ends up in /sys/class/net */
static
CLASS_ATTR
(
bonding_masters
,
S_IWUSR
|
S_IRUGO
,
bonding_show_bonds
,
bonding_store_bonds
);
int
bond_create_slave_symlinks
(
struct
net_device
*
master
,
struct
net_device
*
slave
)
{
char
linkname
[
IFNAMSIZ
+
7
];
int
ret
=
0
;
/* first, create a link from the slave back to the master */
ret
=
sysfs_create_link
(
&
(
slave
->
class_dev
.
kobj
),
&
(
master
->
class_dev
.
kobj
),
"master"
);
if
(
ret
)
return
ret
;
/* next, create a link from the master to the slave */
sprintf
(
linkname
,
"slave_%s"
,
slave
->
name
);
ret
=
sysfs_create_link
(
&
(
master
->
class_dev
.
kobj
),
&
(
slave
->
class_dev
.
kobj
),
linkname
);
return
ret
;
}
void
bond_destroy_slave_symlinks
(
struct
net_device
*
master
,
struct
net_device
*
slave
)
{
char
linkname
[
IFNAMSIZ
+
7
];
sysfs_remove_link
(
&
(
slave
->
class_dev
.
kobj
),
"master"
);
sprintf
(
linkname
,
"slave_%s"
,
slave
->
name
);
sysfs_remove_link
(
&
(
master
->
class_dev
.
kobj
),
linkname
);
}
/*
* Show the slaves in the current bond.
*/
static
ssize_t
bonding_show_slaves
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
slave
*
slave
;
int
i
,
res
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
read_lock_bh
(
&
bond
->
lock
);
bond_for_each_slave
(
bond
,
slave
,
i
)
{
if
(
res
>
(
PAGE_SIZE
-
IFNAMSIZ
))
{
/* not enough space for another interface name */
if
((
PAGE_SIZE
-
res
)
>
10
)
res
=
PAGE_SIZE
-
10
;
res
+=
sprintf
(
buf
+
res
,
"++more++"
);
break
;
}
res
+=
sprintf
(
buf
+
res
,
"%s "
,
slave
->
dev
->
name
);
}
read_unlock_bh
(
&
bond
->
lock
);
res
+=
sprintf
(
buf
+
res
,
"
\n
"
);
res
++
;
return
res
;
}
/*
* Set the slaves in the current bond. The bond interface must be
* up for this to succeed.
* This function is largely the same flow as bonding_update_bonds().
*/
static
ssize_t
bonding_store_slaves
(
struct
class_device
*
cd
,
const
char
*
buffer
,
size_t
count
)
{
char
command
[
IFNAMSIZ
+
1
]
=
{
0
,
};
char
*
ifname
;
int
i
,
res
,
found
,
ret
=
count
;
struct
slave
*
slave
;
struct
net_device
*
dev
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
/* Quick sanity check -- is the bond interface up? */
if
(
!
(
bond
->
dev
->
flags
&
IFF_UP
))
{
printk
(
KERN_ERR
DRV_NAME
": %s: Unable to update slaves because interface is down.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
/* Note: We can't hold bond->lock here, as bond_create grabs it. */
sscanf
(
buffer
,
"%16s"
,
command
);
/* IFNAMSIZ*/
ifname
=
command
+
1
;
if
((
strlen
(
command
)
<=
1
)
||
!
dev_valid_name
(
ifname
))
goto
err_no_cmd
;
if
(
command
[
0
]
==
'+'
)
{
/* Got a slave name in ifname. Is it already in the list? */
found
=
0
;
read_lock_bh
(
&
bond
->
lock
);
bond_for_each_slave
(
bond
,
slave
,
i
)
if
(
strnicmp
(
slave
->
dev
->
name
,
ifname
,
IFNAMSIZ
)
==
0
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Interface %s is already enslaved!
\n
"
,
bond
->
dev
->
name
,
ifname
);
ret
=
-
EPERM
;
read_unlock_bh
(
&
bond
->
lock
);
goto
out
;
}
read_unlock_bh
(
&
bond
->
lock
);
printk
(
KERN_INFO
DRV_NAME
": %s: Adding slave %s.
\n
"
,
bond
->
dev
->
name
,
ifname
);
dev
=
dev_get_by_name
(
ifname
);
if
(
!
dev
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: Interface %s does not exist!
\n
"
,
bond
->
dev
->
name
,
ifname
);
ret
=
-
EPERM
;
goto
out
;
}
else
dev_put
(
dev
);
if
(
dev
->
flags
&
IFF_UP
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Error: Unable to enslave %s "
"because it is already up.
\n
"
,
bond
->
dev
->
name
,
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
/* If this is the first slave, then we need to set
the master's hardware address to be the same as the
slave's. */
if
(
!
(
*
((
u32
*
)
&
(
bond
->
dev
->
dev_addr
[
0
]))))
{
memcpy
(
bond
->
dev
->
dev_addr
,
dev
->
dev_addr
,
dev
->
addr_len
);
}
/* Set the slave's MTU to match the bond */
if
(
dev
->
mtu
!=
bond
->
dev
->
mtu
)
{
if
(
dev
->
change_mtu
)
{
res
=
dev
->
change_mtu
(
dev
,
bond
->
dev
->
mtu
);
if
(
res
)
{
ret
=
res
;
goto
out
;
}
}
else
{
dev
->
mtu
=
bond
->
dev
->
mtu
;
}
}
rtnl_lock
();
res
=
bond_enslave
(
bond
->
dev
,
dev
);
rtnl_unlock
();
if
(
res
)
{
ret
=
res
;
}
goto
out
;
}
if
(
command
[
0
]
==
'-'
)
{
dev
=
NULL
;
bond_for_each_slave
(
bond
,
slave
,
i
)
if
(
strnicmp
(
slave
->
dev
->
name
,
ifname
,
IFNAMSIZ
)
==
0
)
{
dev
=
slave
->
dev
;
break
;
}
if
(
dev
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: Removing slave %s
\n
"
,
bond
->
dev
->
name
,
dev
->
name
);
rtnl_lock
();
res
=
bond_release
(
bond
->
dev
,
dev
);
rtnl_unlock
();
if
(
res
)
{
ret
=
res
;
goto
out
;
}
/* set the slave MTU to the default */
if
(
dev
->
change_mtu
)
{
dev
->
change_mtu
(
dev
,
1500
);
}
else
{
dev
->
mtu
=
1500
;
}
}
else
{
printk
(
KERN_ERR
DRV_NAME
": unable to remove non-existent slave %s for bond %s.
\n
"
,
ifname
,
bond
->
dev
->
name
);
ret
=
-
ENODEV
;
}
goto
out
;
}
err_no_cmd:
printk
(
KERN_ERR
DRV_NAME
": no command found in slaves file for bond %s. Use +ifname or -ifname.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
slaves
,
S_IRUGO
|
S_IWUSR
,
bonding_show_slaves
,
bonding_store_slaves
);
/*
* Show and set the bonding mode. The bond interface must be down to
* change the mode.
*/
static
ssize_t
bonding_show_mode
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
bonding
*
bond
=
to_bond
(
cd
);
return
sprintf
(
buf
,
"%s %d
\n
"
,
bond_mode_tbl
[
bond
->
params
.
mode
].
modename
,
bond
->
params
.
mode
)
+
1
;
}
static
ssize_t
bonding_store_mode
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
new_value
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
dev
->
flags
&
IFF_UP
)
{
printk
(
KERN_ERR
DRV_NAME
": unable to update mode of %s because interface is up.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
new_value
=
bond_parse_parm
((
char
*
)
buf
,
bond_mode_tbl
);
if
(
new_value
<
0
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Ignoring invalid mode value %.*s.
\n
"
,
bond
->
dev
->
name
,
(
int
)
strlen
(
buf
)
-
1
,
buf
);
ret
=
-
EINVAL
;
goto
out
;
}
else
{
bond
->
params
.
mode
=
new_value
;
bond_set_mode_ops
(
bond
,
bond
->
params
.
mode
);
printk
(
KERN_INFO
DRV_NAME
": %s: setting mode to %s (%d).
\n
"
,
bond
->
dev
->
name
,
bond_mode_tbl
[
new_value
].
modename
,
new_value
);
}
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
mode
,
S_IRUGO
|
S_IWUSR
,
bonding_show_mode
,
bonding_store_mode
);
/*
* Show and set the bonding transmit hash method. The bond interface must be down to
* change the xmit hash policy.
*/
static
ssize_t
bonding_show_xmit_hash
(
struct
class_device
*
cd
,
char
*
buf
)
{
int
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
((
bond
->
params
.
mode
!=
BOND_MODE_XOR
)
&&
(
bond
->
params
.
mode
!=
BOND_MODE_8023AD
))
{
// Not Applicable
count
=
sprintf
(
buf
,
"NA
\n
"
)
+
1
;
}
else
{
count
=
sprintf
(
buf
,
"%s %d
\n
"
,
xmit_hashtype_tbl
[
bond
->
params
.
xmit_policy
].
modename
,
bond
->
params
.
xmit_policy
)
+
1
;
}
return
count
;
}
static
ssize_t
bonding_store_xmit_hash
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
new_value
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
dev
->
flags
&
IFF_UP
)
{
printk
(
KERN_ERR
DRV_NAME
"%s: Interface is up. Unable to update xmit policy.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
if
((
bond
->
params
.
mode
!=
BOND_MODE_XOR
)
&&
(
bond
->
params
.
mode
!=
BOND_MODE_8023AD
))
{
printk
(
KERN_ERR
DRV_NAME
"%s: Transmit hash policy is irrelevant in this mode.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
new_value
=
bond_parse_parm
((
char
*
)
buf
,
xmit_hashtype_tbl
);
if
(
new_value
<
0
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Ignoring invalid xmit hash policy value %.*s.
\n
"
,
bond
->
dev
->
name
,
(
int
)
strlen
(
buf
)
-
1
,
buf
);
ret
=
-
EINVAL
;
goto
out
;
}
else
{
bond
->
params
.
xmit_policy
=
new_value
;
bond_set_mode_ops
(
bond
,
bond
->
params
.
mode
);
printk
(
KERN_INFO
DRV_NAME
": %s: setting xmit hash policy to %s (%d).
\n
"
,
bond
->
dev
->
name
,
xmit_hashtype_tbl
[
new_value
].
modename
,
new_value
);
}
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
xmit_hash_policy
,
S_IRUGO
|
S_IWUSR
,
bonding_show_xmit_hash
,
bonding_store_xmit_hash
);
/*
* Show and set the arp timer interval. There are two tricky bits
* here. First, if ARP monitoring is activated, then we must disable
* MII monitoring. Second, if the ARP timer isn't running, we must
* start it.
*/
static
ssize_t
bonding_show_arp_interval
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
bonding
*
bond
=
to_bond
(
cd
);
return
sprintf
(
buf
,
"%d
\n
"
,
bond
->
params
.
arp_interval
)
+
1
;
}
static
ssize_t
bonding_store_arp_interval
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
new_value
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
sscanf
(
buf
,
"%d"
,
&
new_value
)
!=
1
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: no arp_interval value specified.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
new_value
<
0
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Invalid arp_interval value %d not in range 1-%d; rejected.
\n
"
,
bond
->
dev
->
name
,
new_value
,
INT_MAX
);
ret
=
-
EINVAL
;
goto
out
;
}
printk
(
KERN_INFO
DRV_NAME
": %s: Setting ARP monitoring interval to %d.
\n
"
,
bond
->
dev
->
name
,
new_value
);
bond
->
params
.
arp_interval
=
new_value
;
if
(
bond
->
params
.
miimon
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: ARP monitoring cannot be used with MII monitoring. "
"%s Disabling MII monitoring.
\n
"
,
bond
->
dev
->
name
,
bond
->
dev
->
name
);
bond
->
params
.
miimon
=
0
;
/* Kill MII timer, else it brings bond's link down */
if
(
bond
->
arp_timer
.
function
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: Kill MII timer, else it brings bond's link down...
\n
"
,
bond
->
dev
->
name
);
del_timer_sync
(
&
bond
->
mii_timer
);
}
}
if
(
!
bond
->
params
.
arp_targets
[
0
])
{
printk
(
KERN_INFO
DRV_NAME
": %s: ARP monitoring has been set up, "
"but no ARP targets have been specified.
\n
"
,
bond
->
dev
->
name
);
}
if
(
bond
->
dev
->
flags
&
IFF_UP
)
{
/* If the interface is up, we may need to fire off
* the ARP timer. If the interface is down, the
* timer will get fired off when the open function
* is called.
*/
if
(
bond
->
arp_timer
.
function
)
{
/* The timer's already set up, so fire it off */
mod_timer
(
&
bond
->
arp_timer
,
jiffies
+
1
);
}
else
{
/* Set up the timer. */
init_timer
(
&
bond
->
arp_timer
);
bond
->
arp_timer
.
expires
=
jiffies
+
1
;
bond
->
arp_timer
.
data
=
(
unsigned
long
)
bond
->
dev
;
if
(
bond
->
params
.
mode
==
BOND_MODE_ACTIVEBACKUP
)
{
bond
->
arp_timer
.
function
=
(
void
*
)
&
bond_activebackup_arp_mon
;
}
else
{
bond
->
arp_timer
.
function
=
(
void
*
)
&
bond_loadbalance_arp_mon
;
}
add_timer
(
&
bond
->
arp_timer
);
}
}
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
arp_interval
,
S_IRUGO
|
S_IWUSR
,
bonding_show_arp_interval
,
bonding_store_arp_interval
);
/*
* Show and set the arp targets.
*/
static
ssize_t
bonding_show_arp_targets
(
struct
class_device
*
cd
,
char
*
buf
)
{
int
i
,
res
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
for
(
i
=
0
;
i
<
BOND_MAX_ARP_TARGETS
;
i
++
)
{
if
(
bond
->
params
.
arp_targets
[
i
])
res
+=
sprintf
(
buf
+
res
,
"%u.%u.%u.%u "
,
NIPQUAD
(
bond
->
params
.
arp_targets
[
i
]));
}
if
(
res
)
res
--
;
/* eat the leftover space */
res
+=
sprintf
(
buf
+
res
,
"
\n
"
);
res
++
;
return
res
;
}
static
ssize_t
bonding_store_arp_targets
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
u32
newtarget
;
int
i
=
0
,
done
=
0
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
u32
*
targets
;
targets
=
bond
->
params
.
arp_targets
;
newtarget
=
in_aton
(
buf
+
1
);
/* look for adds */
if
(
buf
[
0
]
==
'+'
)
{
if
((
newtarget
==
0
)
||
(
newtarget
==
INADDR_BROADCAST
))
{
printk
(
KERN_ERR
DRV_NAME
": %s: invalid ARP target %u.%u.%u.%u specified for addition
\n
"
,
bond
->
dev
->
name
,
NIPQUAD
(
newtarget
));
ret
=
-
EINVAL
;
goto
out
;
}
/* look for an empty slot to put the target in, and check for dupes */
for
(
i
=
0
;
(
i
<
BOND_MAX_ARP_TARGETS
);
i
++
)
{
if
(
targets
[
i
]
==
newtarget
)
{
/* duplicate */
printk
(
KERN_ERR
DRV_NAME
": %s: ARP target %u.%u.%u.%u is already present
\n
"
,
bond
->
dev
->
name
,
NIPQUAD
(
newtarget
));
if
(
done
)
targets
[
i
]
=
0
;
ret
=
-
EINVAL
;
goto
out
;
}
if
(
targets
[
i
]
==
0
&&
!
done
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: adding ARP target %d.%d.%d.%d.
\n
"
,
bond
->
dev
->
name
,
NIPQUAD
(
newtarget
));
done
=
1
;
targets
[
i
]
=
newtarget
;
}
}
if
(
!
done
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: ARP target table is full!
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EINVAL
;
goto
out
;
}
}
else
if
(
buf
[
0
]
==
'-'
)
{
if
((
newtarget
==
0
)
||
(
newtarget
==
INADDR_BROADCAST
))
{
printk
(
KERN_ERR
DRV_NAME
": %s: invalid ARP target %d.%d.%d.%d specified for removal
\n
"
,
bond
->
dev
->
name
,
NIPQUAD
(
newtarget
));
ret
=
-
EINVAL
;
goto
out
;
}
for
(
i
=
0
;
(
i
<
BOND_MAX_ARP_TARGETS
);
i
++
)
{
if
(
targets
[
i
]
==
newtarget
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: removing ARP target %d.%d.%d.%d.
\n
"
,
bond
->
dev
->
name
,
NIPQUAD
(
newtarget
));
targets
[
i
]
=
0
;
done
=
1
;
}
}
if
(
!
done
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: unable to remove nonexistent ARP target %d.%d.%d.%d.
\n
"
,
bond
->
dev
->
name
,
NIPQUAD
(
newtarget
));
ret
=
-
EINVAL
;
goto
out
;
}
}
else
{
printk
(
KERN_ERR
DRV_NAME
": no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
arp_ip_target
,
S_IRUGO
|
S_IWUSR
,
bonding_show_arp_targets
,
bonding_store_arp_targets
);
/*
* Show and set the up and down delays. These must be multiples of the
* MII monitoring value, and are stored internally as the multiplier.
* Thus, we must translate to MS for the real world.
*/
static
ssize_t
bonding_show_downdelay
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
bonding
*
bond
=
to_bond
(
cd
);
return
sprintf
(
buf
,
"%d
\n
"
,
bond
->
params
.
downdelay
*
bond
->
params
.
miimon
)
+
1
;
}
static
ssize_t
bonding_store_downdelay
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
new_value
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
!
(
bond
->
params
.
miimon
))
{
printk
(
KERN_ERR
DRV_NAME
": %s: Unable to set down delay as MII monitoring is disabled
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
if
(
sscanf
(
buf
,
"%d"
,
&
new_value
)
!=
1
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: no down delay value specified.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
new_value
<
0
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Invalid down delay value %d not in range %d-%d; rejected.
\n
"
,
bond
->
dev
->
name
,
new_value
,
1
,
INT_MAX
);
ret
=
-
EINVAL
;
goto
out
;
}
else
{
if
((
new_value
%
bond
->
params
.
miimon
)
!=
0
)
{
printk
(
KERN_WARNING
DRV_NAME
": %s: Warning: down delay (%d) is not a multiple "
"of miimon (%d), delay rounded to %d ms
\n
"
,
bond
->
dev
->
name
,
new_value
,
bond
->
params
.
miimon
,
(
new_value
/
bond
->
params
.
miimon
)
*
bond
->
params
.
miimon
);
}
bond
->
params
.
downdelay
=
new_value
/
bond
->
params
.
miimon
;
printk
(
KERN_INFO
DRV_NAME
": %s: Setting down delay to %d.
\n
"
,
bond
->
dev
->
name
,
bond
->
params
.
downdelay
*
bond
->
params
.
miimon
);
}
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
downdelay
,
S_IRUGO
|
S_IWUSR
,
bonding_show_downdelay
,
bonding_store_downdelay
);
static
ssize_t
bonding_show_updelay
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
bonding
*
bond
=
to_bond
(
cd
);
return
sprintf
(
buf
,
"%d
\n
"
,
bond
->
params
.
updelay
*
bond
->
params
.
miimon
)
+
1
;
}
static
ssize_t
bonding_store_updelay
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
new_value
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
!
(
bond
->
params
.
miimon
))
{
printk
(
KERN_ERR
DRV_NAME
": %s: Unable to set up delay as MII monitoring is disabled
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
if
(
sscanf
(
buf
,
"%d"
,
&
new_value
)
!=
1
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: no up delay value specified.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
new_value
<
0
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Invalid down delay value %d not in range %d-%d; rejected.
\n
"
,
bond
->
dev
->
name
,
new_value
,
1
,
INT_MAX
);
ret
=
-
EINVAL
;
goto
out
;
}
else
{
if
((
new_value
%
bond
->
params
.
miimon
)
!=
0
)
{
printk
(
KERN_WARNING
DRV_NAME
": %s: Warning: up delay (%d) is not a multiple "
"of miimon (%d), updelay rounded to %d ms
\n
"
,
bond
->
dev
->
name
,
new_value
,
bond
->
params
.
miimon
,
(
new_value
/
bond
->
params
.
miimon
)
*
bond
->
params
.
miimon
);
}
bond
->
params
.
updelay
=
new_value
/
bond
->
params
.
miimon
;
printk
(
KERN_INFO
DRV_NAME
": %s: Setting up delay to %d.
\n
"
,
bond
->
dev
->
name
,
bond
->
params
.
updelay
*
bond
->
params
.
miimon
);
}
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
updelay
,
S_IRUGO
|
S_IWUSR
,
bonding_show_updelay
,
bonding_store_updelay
);
/*
* Show and set the LACP interval. Interface must be down, and the mode
* must be set to 802.3ad mode.
*/
static
ssize_t
bonding_show_lacp
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
bonding
*
bond
=
to_bond
(
cd
);
return
sprintf
(
buf
,
"%s %d
\n
"
,
bond_lacp_tbl
[
bond
->
params
.
lacp_fast
].
modename
,
bond
->
params
.
lacp_fast
)
+
1
;
}
static
ssize_t
bonding_store_lacp
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
new_value
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
dev
->
flags
&
IFF_UP
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Unable to update LACP rate because interface is up.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
if
(
bond
->
params
.
mode
!=
BOND_MODE_8023AD
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Unable to update LACP rate because bond is not in 802.3ad mode.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EPERM
;
goto
out
;
}
new_value
=
bond_parse_parm
((
char
*
)
buf
,
bond_lacp_tbl
);
if
((
new_value
==
1
)
||
(
new_value
==
0
))
{
bond
->
params
.
lacp_fast
=
new_value
;
printk
(
KERN_INFO
DRV_NAME
": %s: Setting LACP rate to %s (%d).
\n
"
,
bond
->
dev
->
name
,
bond_lacp_tbl
[
new_value
].
modename
,
new_value
);
}
else
{
printk
(
KERN_ERR
DRV_NAME
": %s: Ignoring invalid LACP rate value %.*s.
\n
"
,
bond
->
dev
->
name
,
(
int
)
strlen
(
buf
)
-
1
,
buf
);
ret
=
-
EINVAL
;
}
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
lacp_rate
,
S_IRUGO
|
S_IWUSR
,
bonding_show_lacp
,
bonding_store_lacp
);
/*
* Show and set the MII monitor interval. There are two tricky bits
* here. First, if MII monitoring is activated, then we must disable
* ARP monitoring. Second, if the timer isn't running, we must
* start it.
*/
static
ssize_t
bonding_show_miimon
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
bonding
*
bond
=
to_bond
(
cd
);
return
sprintf
(
buf
,
"%d
\n
"
,
bond
->
params
.
miimon
)
+
1
;
}
static
ssize_t
bonding_store_miimon
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
new_value
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
sscanf
(
buf
,
"%d"
,
&
new_value
)
!=
1
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: no miimon value specified.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
new_value
<
0
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: Invalid miimon value %d not in range %d-%d; rejected.
\n
"
,
bond
->
dev
->
name
,
new_value
,
1
,
INT_MAX
);
ret
=
-
EINVAL
;
goto
out
;
}
else
{
printk
(
KERN_INFO
DRV_NAME
": %s: Setting MII monitoring interval to %d.
\n
"
,
bond
->
dev
->
name
,
new_value
);
bond
->
params
.
miimon
=
new_value
;
if
(
bond
->
params
.
updelay
)
printk
(
KERN_INFO
DRV_NAME
": %s: Note: Updating updelay (to %d) "
"since it is a multiple of the miimon value.
\n
"
,
bond
->
dev
->
name
,
bond
->
params
.
updelay
*
bond
->
params
.
miimon
);
if
(
bond
->
params
.
downdelay
)
printk
(
KERN_INFO
DRV_NAME
": %s: Note: Updating downdelay (to %d) "
"since it is a multiple of the miimon value.
\n
"
,
bond
->
dev
->
name
,
bond
->
params
.
downdelay
*
bond
->
params
.
miimon
);
if
(
bond
->
params
.
arp_interval
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: MII monitoring cannot be used with "
"ARP monitoring. Disabling ARP monitoring...
\n
"
,
bond
->
dev
->
name
);
bond
->
params
.
arp_interval
=
0
;
/* Kill ARP timer, else it brings bond's link down */
if
(
bond
->
mii_timer
.
function
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: Kill ARP timer, else it brings bond's link down...
\n
"
,
bond
->
dev
->
name
);
del_timer_sync
(
&
bond
->
arp_timer
);
}
}
if
(
bond
->
dev
->
flags
&
IFF_UP
)
{
/* If the interface is up, we may need to fire off
* the MII timer. If the interface is down, the
* timer will get fired off when the open function
* is called.
*/
if
(
bond
->
mii_timer
.
function
)
{
/* The timer's already set up, so fire it off */
mod_timer
(
&
bond
->
mii_timer
,
jiffies
+
1
);
}
else
{
/* Set up the timer. */
init_timer
(
&
bond
->
mii_timer
);
bond
->
mii_timer
.
expires
=
jiffies
+
1
;
bond
->
mii_timer
.
data
=
(
unsigned
long
)
bond
->
dev
;
bond
->
mii_timer
.
function
=
(
void
*
)
&
bond_mii_monitor
;
add_timer
(
&
bond
->
mii_timer
);
}
}
}
out:
return
ret
;
}
static
CLASS_DEVICE_ATTR
(
miimon
,
S_IRUGO
|
S_IWUSR
,
bonding_show_miimon
,
bonding_store_miimon
);
/*
* Show and set the primary slave. The store function is much
* simpler than bonding_store_slaves function because it only needs to
* handle one interface name.
* The bond must be a mode that supports a primary for this be
* set.
*/
static
ssize_t
bonding_show_primary
(
struct
class_device
*
cd
,
char
*
buf
)
{
int
count
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
primary_slave
)
count
=
sprintf
(
buf
,
"%s
\n
"
,
bond
->
primary_slave
->
dev
->
name
)
+
1
;
else
count
=
sprintf
(
buf
,
"
\n
"
)
+
1
;
return
count
;
}
static
ssize_t
bonding_store_primary
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
i
;
struct
slave
*
slave
;
struct
bonding
*
bond
=
to_bond
(
cd
);
write_lock_bh
(
&
bond
->
lock
);
if
(
!
USES_PRIMARY
(
bond
->
params
.
mode
))
{
printk
(
KERN_INFO
DRV_NAME
": %s: Unable to set primary slave; %s is in mode %d
\n
"
,
bond
->
dev
->
name
,
bond
->
dev
->
name
,
bond
->
params
.
mode
);
}
else
{
bond_for_each_slave
(
bond
,
slave
,
i
)
{
if
(
strnicmp
(
slave
->
dev
->
name
,
buf
,
strlen
(
slave
->
dev
->
name
))
==
0
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: Setting %s as primary slave.
\n
"
,
bond
->
dev
->
name
,
slave
->
dev
->
name
);
bond
->
primary_slave
=
slave
;
bond_select_active_slave
(
bond
);
goto
out
;
}
}
/* if we got here, then we didn't match the name of any slave */
if
(
strlen
(
buf
)
==
0
||
buf
[
0
]
==
'\n'
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: Setting primary slave to None.
\n
"
,
bond
->
dev
->
name
);
bond
->
primary_slave
=
0
;
bond_select_active_slave
(
bond
);
}
else
{
printk
(
KERN_INFO
DRV_NAME
": %s: Unable to set %.*s as primary slave as it is not a slave.
\n
"
,
bond
->
dev
->
name
,
(
int
)
strlen
(
buf
)
-
1
,
buf
);
}
}
out:
write_unlock_bh
(
&
bond
->
lock
);
return
count
;
}
static
CLASS_DEVICE_ATTR
(
primary
,
S_IRUGO
|
S_IWUSR
,
bonding_show_primary
,
bonding_store_primary
);
/*
* Show and set the use_carrier flag.
*/
static
ssize_t
bonding_show_carrier
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
bonding
*
bond
=
to_bond
(
cd
);
return
sprintf
(
buf
,
"%d
\n
"
,
bond
->
params
.
use_carrier
)
+
1
;
}
static
ssize_t
bonding_store_carrier
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
new_value
,
ret
=
count
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
sscanf
(
buf
,
"%d"
,
&
new_value
)
!=
1
)
{
printk
(
KERN_ERR
DRV_NAME
": %s: no use_carrier value specified.
\n
"
,
bond
->
dev
->
name
);
ret
=
-
EINVAL
;
goto
out
;
}
if
((
new_value
==
0
)
||
(
new_value
==
1
))
{
bond
->
params
.
use_carrier
=
new_value
;
printk
(
KERN_INFO
DRV_NAME
": %s: Setting use_carrier to %d.
\n
"
,
bond
->
dev
->
name
,
new_value
);
}
else
{
printk
(
KERN_INFO
DRV_NAME
": %s: Ignoring invalid use_carrier value %d.
\n
"
,
bond
->
dev
->
name
,
new_value
);
}
out:
return
count
;
}
static
CLASS_DEVICE_ATTR
(
use_carrier
,
S_IRUGO
|
S_IWUSR
,
bonding_show_carrier
,
bonding_store_carrier
);
/*
* Show and set currently active_slave.
*/
static
ssize_t
bonding_show_active_slave
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
slave
*
curr
;
struct
bonding
*
bond
=
to_bond
(
cd
);
int
count
;
read_lock
(
&
bond
->
curr_slave_lock
);
curr
=
bond
->
curr_active_slave
;
read_unlock
(
&
bond
->
curr_slave_lock
);
if
(
USES_PRIMARY
(
bond
->
params
.
mode
)
&&
curr
)
count
=
sprintf
(
buf
,
"%s
\n
"
,
curr
->
dev
->
name
)
+
1
;
else
count
=
sprintf
(
buf
,
"
\n
"
)
+
1
;
return
count
;
}
static
ssize_t
bonding_store_active_slave
(
struct
class_device
*
cd
,
const
char
*
buf
,
size_t
count
)
{
int
i
;
struct
slave
*
slave
;
struct
slave
*
old_active
=
NULL
;
struct
slave
*
new_active
=
NULL
;
struct
bonding
*
bond
=
to_bond
(
cd
);
write_lock_bh
(
&
bond
->
lock
);
if
(
!
USES_PRIMARY
(
bond
->
params
.
mode
))
{
printk
(
KERN_INFO
DRV_NAME
": %s: Unable to change active slave; %s is in mode %d
\n
"
,
bond
->
dev
->
name
,
bond
->
dev
->
name
,
bond
->
params
.
mode
);
}
else
{
bond_for_each_slave
(
bond
,
slave
,
i
)
{
if
(
strnicmp
(
slave
->
dev
->
name
,
buf
,
strlen
(
slave
->
dev
->
name
))
==
0
)
{
old_active
=
bond
->
curr_active_slave
;
new_active
=
slave
;
if
(
new_active
&&
(
new_active
==
old_active
))
{
/* do nothing */
printk
(
KERN_INFO
DRV_NAME
": %s: %s is already the current active slave.
\n
"
,
bond
->
dev
->
name
,
slave
->
dev
->
name
);
goto
out
;
}
else
{
if
((
new_active
)
&&
(
old_active
)
&&
(
new_active
->
link
==
BOND_LINK_UP
)
&&
IS_UP
(
new_active
->
dev
))
{
printk
(
KERN_INFO
DRV_NAME
": %s: Setting %s as active slave.
\n
"
,
bond
->
dev
->
name
,
slave
->
dev
->
name
);
bond_change_active_slave
(
bond
,
new_active
);
}
else
{
printk
(
KERN_INFO
DRV_NAME
": %s: Could not set %s as active slave; "
"either %s is down or the link is down.
\n
"
,
bond
->
dev
->
name
,
slave
->
dev
->
name
,
slave
->
dev
->
name
);
}
goto
out
;
}
}
}
/* if we got here, then we didn't match the name of any slave */
if
(
strlen
(
buf
)
==
0
||
buf
[
0
]
==
'\n'
)
{
printk
(
KERN_INFO
DRV_NAME
": %s: Setting active slave to None.
\n
"
,
bond
->
dev
->
name
);
bond
->
primary_slave
=
0
;
bond_select_active_slave
(
bond
);
}
else
{
printk
(
KERN_INFO
DRV_NAME
": %s: Unable to set %.*s as active slave as it is not a slave.
\n
"
,
bond
->
dev
->
name
,
(
int
)
strlen
(
buf
)
-
1
,
buf
);
}
}
out:
write_unlock_bh
(
&
bond
->
lock
);
return
count
;
}
static
CLASS_DEVICE_ATTR
(
active_slave
,
S_IRUGO
|
S_IWUSR
,
bonding_show_active_slave
,
bonding_store_active_slave
);
/*
* Show link status of the bond interface.
*/
static
ssize_t
bonding_show_mii_status
(
struct
class_device
*
cd
,
char
*
buf
)
{
struct
slave
*
curr
;
struct
bonding
*
bond
=
to_bond
(
cd
);
read_lock
(
&
bond
->
curr_slave_lock
);
curr
=
bond
->
curr_active_slave
;
read_unlock
(
&
bond
->
curr_slave_lock
);
return
sprintf
(
buf
,
"%s
\n
"
,
(
curr
)
?
"up"
:
"down"
)
+
1
;
}
static
CLASS_DEVICE_ATTR
(
mii_status
,
S_IRUGO
,
bonding_show_mii_status
,
NULL
);
/*
* Show current 802.3ad aggregator ID.
*/
static
ssize_t
bonding_show_ad_aggregator
(
struct
class_device
*
cd
,
char
*
buf
)
{
int
count
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
params
.
mode
==
BOND_MODE_8023AD
)
{
struct
ad_info
ad_info
;
count
=
sprintf
(
buf
,
"%d
\n
"
,
(
bond_3ad_get_active_agg_info
(
bond
,
&
ad_info
))
?
0
:
ad_info
.
aggregator_id
)
+
1
;
}
else
count
=
sprintf
(
buf
,
"
\n
"
)
+
1
;
return
count
;
}
static
CLASS_DEVICE_ATTR
(
ad_aggregator
,
S_IRUGO
,
bonding_show_ad_aggregator
,
NULL
);
/*
* Show number of active 802.3ad ports.
*/
static
ssize_t
bonding_show_ad_num_ports
(
struct
class_device
*
cd
,
char
*
buf
)
{
int
count
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
params
.
mode
==
BOND_MODE_8023AD
)
{
struct
ad_info
ad_info
;
count
=
sprintf
(
buf
,
"%d
\n
"
,
(
bond_3ad_get_active_agg_info
(
bond
,
&
ad_info
))
?
0
:
ad_info
.
ports
)
+
1
;
}
else
count
=
sprintf
(
buf
,
"
\n
"
)
+
1
;
return
count
;
}
static
CLASS_DEVICE_ATTR
(
ad_num_ports
,
S_IRUGO
,
bonding_show_ad_num_ports
,
NULL
);
/*
* Show current 802.3ad actor key.
*/
static
ssize_t
bonding_show_ad_actor_key
(
struct
class_device
*
cd
,
char
*
buf
)
{
int
count
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
params
.
mode
==
BOND_MODE_8023AD
)
{
struct
ad_info
ad_info
;
count
=
sprintf
(
buf
,
"%d
\n
"
,
(
bond_3ad_get_active_agg_info
(
bond
,
&
ad_info
))
?
0
:
ad_info
.
actor_key
)
+
1
;
}
else
count
=
sprintf
(
buf
,
"
\n
"
)
+
1
;
return
count
;
}
static
CLASS_DEVICE_ATTR
(
ad_actor_key
,
S_IRUGO
,
bonding_show_ad_actor_key
,
NULL
);
/*
* Show current 802.3ad partner key.
*/
static
ssize_t
bonding_show_ad_partner_key
(
struct
class_device
*
cd
,
char
*
buf
)
{
int
count
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
params
.
mode
==
BOND_MODE_8023AD
)
{
struct
ad_info
ad_info
;
count
=
sprintf
(
buf
,
"%d
\n
"
,
(
bond_3ad_get_active_agg_info
(
bond
,
&
ad_info
))
?
0
:
ad_info
.
partner_key
)
+
1
;
}
else
count
=
sprintf
(
buf
,
"
\n
"
)
+
1
;
return
count
;
}
static
CLASS_DEVICE_ATTR
(
ad_partner_key
,
S_IRUGO
,
bonding_show_ad_partner_key
,
NULL
);
/*
* Show current 802.3ad partner mac.
*/
static
ssize_t
bonding_show_ad_partner_mac
(
struct
class_device
*
cd
,
char
*
buf
)
{
int
count
=
0
;
struct
bonding
*
bond
=
to_bond
(
cd
);
if
(
bond
->
params
.
mode
==
BOND_MODE_8023AD
)
{
struct
ad_info
ad_info
;
if
(
!
bond_3ad_get_active_agg_info
(
bond
,
&
ad_info
))
{
count
=
sprintf
(
buf
,
"%02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
ad_info
.
partner_system
[
0
],
ad_info
.
partner_system
[
1
],
ad_info
.
partner_system
[
2
],
ad_info
.
partner_system
[
3
],
ad_info
.
partner_system
[
4
],
ad_info
.
partner_system
[
5
])
+
1
;
}
}
else
count
=
sprintf
(
buf
,
"
\n
"
)
+
1
;
return
count
;
}
static
CLASS_DEVICE_ATTR
(
ad_partner_mac
,
S_IRUGO
,
bonding_show_ad_partner_mac
,
NULL
);
static
struct
attribute
*
per_bond_attrs
[]
=
{
&
class_device_attr_slaves
.
attr
,
&
class_device_attr_mode
.
attr
,
&
class_device_attr_arp_interval
.
attr
,
&
class_device_attr_arp_ip_target
.
attr
,
&
class_device_attr_downdelay
.
attr
,
&
class_device_attr_updelay
.
attr
,
&
class_device_attr_lacp_rate
.
attr
,
&
class_device_attr_xmit_hash_policy
.
attr
,
&
class_device_attr_miimon
.
attr
,
&
class_device_attr_primary
.
attr
,
&
class_device_attr_use_carrier
.
attr
,
&
class_device_attr_active_slave
.
attr
,
&
class_device_attr_mii_status
.
attr
,
&
class_device_attr_ad_aggregator
.
attr
,
&
class_device_attr_ad_num_ports
.
attr
,
&
class_device_attr_ad_actor_key
.
attr
,
&
class_device_attr_ad_partner_key
.
attr
,
&
class_device_attr_ad_partner_mac
.
attr
,
NULL
,
};
static
struct
attribute_group
bonding_group
=
{
.
name
=
"bonding"
,
.
attrs
=
per_bond_attrs
,
};
/*
* Initialize sysfs. This sets up the bonding_masters file in
* /sys/class/net.
*/
int
bond_create_sysfs
(
void
)
{
int
ret
=
0
;
struct
bonding
*
firstbond
;
init_rwsem
(
&
bonding_rwsem
);
/* get the netdev class pointer */
firstbond
=
container_of
(
bond_dev_list
.
next
,
struct
bonding
,
bond_list
);
if
(
!
firstbond
)
return
-
ENODEV
;
netdev_class
=
firstbond
->
dev
->
class_dev
.
class
;
if
(
!
netdev_class
)
return
-
ENODEV
;
ret
=
class_create_file
(
netdev_class
,
&
class_attr_bonding_masters
);
return
ret
;
}
/*
* Remove /sys/class/net/bonding_masters.
*/
void
bond_destroy_sysfs
(
void
)
{
if
(
netdev_class
)
class_remove_file
(
netdev_class
,
&
class_attr_bonding_masters
);
}
/*
* Initialize sysfs for each bond. This sets up and registers
* the 'bondctl' directory for each individual bond under /sys/class/net.
*/
int
bond_create_sysfs_entry
(
struct
bonding
*
bond
)
{
struct
net_device
*
dev
=
bond
->
dev
;
int
err
;
err
=
sysfs_create_group
(
&
(
dev
->
class_dev
.
kobj
),
&
bonding_group
);
if
(
err
)
{
printk
(
KERN_EMERG
"eek! didn't create group!
\n
"
);
}
if
(
expected_refcount
<
1
)
expected_refcount
=
atomic_read
(
&
bond
->
dev
->
class_dev
.
kobj
.
kref
.
refcount
);
return
err
;
}
/*
* Remove sysfs entries for each bond.
*/
void
bond_destroy_sysfs_entry
(
struct
bonding
*
bond
)
{
struct
net_device
*
dev
=
bond
->
dev
;
sysfs_remove_group
(
&
(
dev
->
class_dev
.
kobj
),
&
bonding_group
);
}
drivers/net/bonding/bonding.h
View file @
83cbd33a
...
...
@@ -29,6 +29,10 @@
* 2005/05/05 - Jason Gabler <jygabler at lbl dot gov>
* - added "xmit_policy" kernel parameter for alternate hashing policy
* support for mode 2
*
* 2005/09/27 - Mitch Williams <mitch.a.williams at intel dot com>
* Radheka Godse <radheka.godse at intel dot com>
* - Added bonding sysfs interface
*/
#ifndef _LINUX_BONDING_H
...
...
@@ -37,11 +41,12 @@
#include <linux/timer.h>
#include <linux/proc_fs.h>
#include <linux/if_bonding.h>
#include <linux/kobject.h>
#include "bond_3ad.h"
#include "bond_alb.h"
#define DRV_VERSION "
2.6.5
"
#define DRV_RELDATE "November
4
, 2005"
#define DRV_VERSION "
3.0.0
"
#define DRV_RELDATE "November
8
, 2005"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
...
...
@@ -152,6 +157,11 @@ struct bond_params {
u32
arp_targets
[
BOND_MAX_ARP_TARGETS
];
};
struct
bond_parm_tbl
{
char
*
modename
;
int
mode
;
};
struct
vlan_entry
{
struct
list_head
vlan_list
;
u32
vlan_ip
;
...
...
@@ -159,7 +169,7 @@ struct vlan_entry {
};
struct
slave
{
struct
net_device
*
dev
;
/* first - useful
l
for panic debug */
struct
net_device
*
dev
;
/* first - useful for panic debug */
struct
slave
*
next
;
struct
slave
*
prev
;
s16
delay
;
...
...
@@ -185,7 +195,7 @@ struct slave {
* beforehand.
*/
struct
bonding
{
struct
net_device
*
dev
;
/* first - useful
l
for panic debug */
struct
net_device
*
dev
;
/* first - useful for panic debug */
struct
slave
*
first_slave
;
struct
slave
*
curr_active_slave
;
struct
slave
*
current_arp_slave
;
...
...
@@ -255,6 +265,25 @@ extern inline void bond_set_slave_active_flags(struct slave *slave)
struct
vlan_entry
*
bond_next_vlan
(
struct
bonding
*
bond
,
struct
vlan_entry
*
curr
);
int
bond_dev_queue_xmit
(
struct
bonding
*
bond
,
struct
sk_buff
*
skb
,
struct
net_device
*
slave_dev
);
int
bond_create
(
char
*
name
,
struct
bond_params
*
params
,
struct
bonding
**
newbond
);
void
bond_deinit
(
struct
net_device
*
bond_dev
);
int
bond_create_sysfs
(
void
);
void
bond_destroy_sysfs
(
void
);
void
bond_destroy_sysfs_entry
(
struct
bonding
*
bond
);
int
bond_create_sysfs_entry
(
struct
bonding
*
bond
);
int
bond_create_slave_symlinks
(
struct
net_device
*
master
,
struct
net_device
*
slave
);
void
bond_destroy_slave_symlinks
(
struct
net_device
*
master
,
struct
net_device
*
slave
);
int
bond_enslave
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
);
int
bond_release
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
);
int
bond_sethwaddr
(
struct
net_device
*
bond_dev
,
struct
net_device
*
slave_dev
);
void
bond_mii_monitor
(
struct
net_device
*
bond_dev
);
void
bond_loadbalance_arp_mon
(
struct
net_device
*
bond_dev
);
void
bond_activebackup_arp_mon
(
struct
net_device
*
bond_dev
);
void
bond_set_mode_ops
(
struct
bonding
*
bond
,
int
mode
);
int
bond_parse_parm
(
char
*
mode_arg
,
struct
bond_parm_tbl
*
tbl
);
const
char
*
bond_mode_name
(
int
mode
);
void
bond_select_active_slave
(
struct
bonding
*
bond
);
void
bond_change_active_slave
(
struct
bonding
*
bond
,
struct
slave
*
new_active
);
#endif
/* _LINUX_BONDING_H */
include/linux/netdevice.h
View file @
83cbd33a
...
...
@@ -684,6 +684,7 @@ extern int netif_rx(struct sk_buff *skb);
extern
int
netif_rx_ni
(
struct
sk_buff
*
skb
);
#define HAVE_NETIF_RECEIVE_SKB 1
extern
int
netif_receive_skb
(
struct
sk_buff
*
skb
);
extern
int
dev_valid_name
(
const
char
*
name
);
extern
int
dev_ioctl
(
unsigned
int
cmd
,
void
__user
*
);
extern
int
dev_ethtool
(
struct
ifreq
*
);
extern
unsigned
dev_get_flags
(
const
struct
net_device
*
);
...
...
net/core/dev.c
View file @
83cbd33a
...
...
@@ -626,7 +626,7 @@ struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mas
* Network device names need to be valid file names to
* to allow sysfs to work
*/
static
int
dev_valid_name
(
const
char
*
name
)
int
dev_valid_name
(
const
char
*
name
)
{
return
!
(
*
name
==
'\0'
||
!
strcmp
(
name
,
"."
)
...
...
@@ -3269,6 +3269,7 @@ EXPORT_SYMBOL(__dev_get_by_index);
EXPORT_SYMBOL
(
__dev_get_by_name
);
EXPORT_SYMBOL
(
__dev_remove_pack
);
EXPORT_SYMBOL
(
__skb_linearize
);
EXPORT_SYMBOL
(
dev_valid_name
);
EXPORT_SYMBOL
(
dev_add_pack
);
EXPORT_SYMBOL
(
dev_alloc_name
);
EXPORT_SYMBOL
(
dev_close
);
...
...
net/core/utils.c
View file @
83cbd33a
...
...
@@ -175,7 +175,7 @@ __u32 in_aton(const char *str)
if
(
*
str
!=
'\0'
)
{
val
=
0
;
while
(
*
str
!=
'\0'
&&
*
str
!=
'.'
)
while
(
*
str
!=
'\0'
&&
*
str
!=
'.'
&&
*
str
!=
'\n'
)
{
val
*=
10
;
val
+=
*
str
-
'0'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment