~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/net/bonding.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * originally based on the dummy device.
  3  *
  4  * Copyright 1999, Thomas Davis, tadavis@lbl.gov.  
  5  * Licensed under the GPL. Based on dummy.c, and eql.c devices.
  6  *
  7  * bond.c: a bonding/etherchannel/sun trunking net driver
  8  *
  9  * This is useful to talk to a Cisco 5500, running Etherchannel, aka:
 10  *      Linux Channel Bonding
 11  *      Sun Trunking (Solaris)
 12  *
 13  * How it works:
 14  *    ifconfig bond0 ipaddress netmask up
 15  *      will setup a network device, with an ip address.  No mac address 
 16  *      will be assigned at this time.  The hw mac address will come from 
 17  *      the first slave bonded to the channel.  All slaves will then use 
 18  *      this hw mac address.
 19  *
 20  *    ifconfig bond0 down
 21  *         will release all slaves, marking them as down.
 22  *
 23  *    ifenslave bond0 eth0
 24  *      will attache eth0 to bond0 as a slave.  eth0 hw mac address will either
 25  *      a: be used as initial mac address
 26  *      b: if a hw mac address already is there, eth0's hw mac address 
 27  *         will then  be set from bond0.
 28  *
 29  * v0.1 - first working version.
 30  * v0.2 - changed stats to be calculated by summing slaves stats.
 31  * 
 32  */
 33 
 34 #include <linux/module.h>
 35 #include <linux/kernel.h>
 36 #include <linux/netdevice.h>
 37 #include <linux/init.h>
 38 #include <linux/if_bonding.h>
 39 
 40 typedef struct slave
 41 {
 42         struct slave *next;
 43         struct slave *prev;
 44         struct net_device *dev;
 45 } slave_t;
 46 
 47 typedef struct bonding
 48 {
 49         slave_t *next;
 50         slave_t *prev;
 51         struct net_device *master;
 52 
 53         slave_t *current_slave;
 54         struct net_device_stats stats;
 55 } bonding_t;
 56 
 57 
 58 static int bond_xmit(struct sk_buff *skb, struct net_device *dev);
 59 static struct net_device_stats *bond_get_stats(struct net_device *dev);
 60 
 61 static struct net_device *this_bond;
 62 
 63 static int bond_open(struct net_device *dev)
 64 {
 65         MOD_INC_USE_COUNT;
 66         return 0;
 67 }
 68 
 69 static void release_one_slave(struct net_device *master, slave_t *slave)
 70 {
 71         bonding_t *bond = master->priv;
 72 
 73         spin_lock_bh(&master->xmit_lock);
 74         if (bond->current_slave == slave)
 75                 bond->current_slave = slave->next;
 76         slave->next->prev = slave->prev;
 77         slave->prev->next = slave->next;
 78         spin_unlock_bh(&master->xmit_lock);
 79 
 80         netdev_set_master(slave->dev, NULL);
 81 
 82         dev_put(slave->dev);
 83         kfree(slave);
 84         MOD_DEC_USE_COUNT;
 85 }
 86 
 87 static int bond_close(struct net_device *master)
 88 {
 89         bonding_t *bond = master->priv;
 90         slave_t *slave;
 91 
 92         while ((slave = bond->next) != (slave_t*)bond)
 93                 release_one_slave(master, slave);
 94 
 95         MOD_DEC_USE_COUNT;
 96         return 0;
 97 }
 98 
 99 static void bond_set_multicast_list(struct net_device *master)
100 {
101         bonding_t *bond = master->priv;
102         slave_t *slave;
103 
104         for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) {
105                 slave->dev->mc_list = master->mc_list;
106                 slave->dev->mc_count = master->mc_count;
107                 slave->dev->flags = master->flags;
108                 slave->dev->set_multicast_list(slave->dev);
109         }
110 }
111 
112 static int bond_enslave(struct net_device *master, struct net_device *dev)
113 {
114         int err;
115         bonding_t *bond = master->priv;
116         slave_t *slave;
117 
118         if (dev->type != master->type)
119                 return -ENODEV;
120 
121         if ((slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL)
122                 return -ENOMEM;
123 
124         memset(slave, 0, sizeof(slave_t));
125 
126         err = netdev_set_master(dev, master);
127         if (err) {
128                 kfree(slave);
129                 return err;
130         }
131 
132         slave->dev = dev;
133 
134         spin_lock_bh(&master->xmit_lock);
135 
136         dev_hold(dev);
137 
138         slave->prev = bond->prev;
139         slave->next = (slave_t*)bond;
140         slave->prev->next = slave;
141         slave->next->prev = slave;
142 
143         spin_unlock_bh(&master->xmit_lock);
144 
145         MOD_INC_USE_COUNT;
146         return 0;
147 }
148 
149 static int bond_release(struct net_device *master, struct net_device *dev)
150 {
151         bonding_t *bond = master->priv;
152         slave_t *slave;
153 
154         if (dev->master != master)
155                 return -EINVAL;
156 
157         for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) {
158                 if (slave->dev == dev) {
159                         release_one_slave(master, slave);
160                         break;
161                 }
162         }
163 
164         return 0;
165 }
166 
167 /* It is pretty silly, SIOCSIFHWADDR exists to make this. */
168 
169 static int bond_sethwaddr(struct net_device *master, struct net_device *slave)
170 {
171         memcpy(master->dev_addr, slave->dev_addr, slave->addr_len);
172         return 0;
173 }
174 
175 static int bond_ioctl(struct net_device *master, struct ifreq *ifr, int cmd)
176 {
177         struct net_device *slave = __dev_get_by_name(ifr->ifr_slave);
178 
179         if (slave == NULL)
180                 return -ENODEV;
181 
182         switch (cmd) {
183         case BOND_ENSLAVE:
184                 return bond_enslave(master, slave);
185         case BOND_RELEASE:
186                 return bond_release(master, slave);
187         case BOND_SETHWADDR:
188                 return bond_sethwaddr(master, slave);
189         default:
190                 return -EOPNOTSUPP;
191         }
192 }
193 
194 static int bond_event(struct notifier_block *this, unsigned long event, void *ptr)
195 {
196         struct net_device *slave = ptr;
197 
198         if (this_bond == NULL ||
199             this_bond == slave ||
200             this_bond != slave->master)
201                 return NOTIFY_DONE;
202 
203         switch (event) {
204         case NETDEV_UNREGISTER:
205                 bond_release(this_bond, slave);
206                 break;
207         }
208 
209         return NOTIFY_DONE;
210 }
211 
212 static struct notifier_block bond_netdev_notifier={
213         bond_event,
214         NULL,
215         0
216 };
217 
218 static int __init bond_init(struct net_device *dev)
219 {
220         bonding_t *bond;
221 
222         bond = kmalloc(sizeof(struct bonding), GFP_KERNEL);
223         if (bond == NULL)
224                 return -ENOMEM;
225 
226         memset(bond, 0, sizeof(struct bonding));
227         bond->next = (slave_t*)bond;
228         bond->prev = (slave_t*)bond;
229         bond->master = dev;
230         bond->current_slave = (slave_t*)bond;
231         dev->priv = bond;
232 
233         /* Initialize the device structure. */
234         dev->hard_start_xmit = bond_xmit;
235         dev->get_stats  = bond_get_stats;
236         dev->open = bond_open;
237         dev->stop = bond_close;
238         dev->set_multicast_list = bond_set_multicast_list;
239         dev->do_ioctl = bond_ioctl;
240 
241         /* Fill in the fields of the device structure with ethernet-generic 
242            values. */
243         ether_setup(dev);
244         dev->tx_queue_len = 0;
245         dev->flags |= IFF_MASTER;
246 
247         this_bond = dev;
248 
249         register_netdevice_notifier(&bond_netdev_notifier);
250 
251         return 0;
252 }
253 
254 static int bond_xmit(struct sk_buff *skb, struct net_device *dev)
255 {
256         bonding_t *bond = dev->priv;
257         slave_t *slave, *start_at;
258         int pkt_len = skb->len;
259 
260         slave = start_at = bond->current_slave;
261 
262         do {
263                 if (slave == (slave_t*)bond)
264                         continue;
265 
266                 if (netif_running(slave->dev) && netif_carrier_ok(slave->dev)) {
267                         bond->current_slave = slave->next;
268                         skb->dev = slave->dev;
269 
270                         if (dev_queue_xmit(skb)) {
271                                 bond->stats.tx_dropped++;
272                         } else {
273                                 bond->stats.tx_packets++;
274                                 bond->stats.tx_bytes += pkt_len;
275                         }
276                         return 0;
277                 }
278         } while ((slave = slave->next) != start_at);
279 
280         bond->stats.tx_dropped++;
281         kfree_skb(skb);
282         return 0;
283 }
284 
285 static struct net_device_stats *bond_get_stats(struct net_device *dev)
286 {
287         bonding_t *bond = dev->priv;
288 
289         return &bond->stats;
290 }
291 
292 static struct net_device dev_bond = {
293                 "",
294                 0, 0, 0, 0,
295                 0x0, 0,
296                 0, 0, 0, NULL, bond_init };
297 
298 static int __init bonding_init(void)
299 {
300         /* Find a name for this unit */
301         int err=dev_alloc_name(&dev_bond,"bond%d");
302 
303         if (err<0)
304                 return err;
305 
306         if (register_netdev(&dev_bond) != 0)
307                 return -EIO;
308 
309         return 0;
310 }
311 
312 static void __exit bonding_exit(void)
313 {
314         unregister_netdevice_notifier(&bond_netdev_notifier);
315 
316         unregister_netdev(&dev_bond);
317 
318         kfree(dev_bond.priv);
319 }
320 
321 module_init(bonding_init);
322 module_exit(bonding_exit);
323 
324 /*
325  * Local variables:
326  *  c-indent-level: 8
327  *  c-basic-offset: 8
328  *  tab-width: 8
329  * End:
330  */
331 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.