📄 bonding.c
字号:
if (!IS_UP(dev)) { /* bond down */ dev_kfree_skb(skb); return 0; } read_lock_irqsave(&bond->lock, flags); read_lock(&bond->ptrlock); slave = start_at = bond->current_slave; read_unlock(&bond->ptrlock); if (slave == NULL) { /* we're at the root, get the first slave */ /* no suitable interface, frame not sent */ dev_kfree_skb(skb); read_unlock_irqrestore(&bond->lock, flags); return 0; } do { if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { skb->dev = slave->dev; skb->priority = 1; dev_queue_xmit(skb); write_lock(&bond->ptrlock); bond->current_slave = slave->next; write_unlock(&bond->ptrlock); read_unlock_irqrestore(&bond->lock, flags); return 0; } } while ((slave = slave->next) != start_at); /* no suitable interface, frame not sent */ dev_kfree_skb(skb); read_unlock_irqrestore(&bond->lock, flags); return 0;}/* * in XOR mode, we determine the output device by performing xor on * the source and destination hw adresses. If this device is not * enabled, find the next slave following this xor slave. */static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev){ slave_t *slave, *start_at; struct bonding *bond = (struct bonding *) dev->priv; unsigned long flags; struct ethhdr *data = (struct ethhdr *)skb->data; int slave_no; if (!IS_UP(dev)) { /* bond down */ dev_kfree_skb(skb); return 0; } read_lock_irqsave(&bond->lock, flags); slave = bond->prev; /* we're at the root, get the first slave */ if ((slave == NULL) || (slave->dev == NULL)) { /* no suitable interface, frame not sent */ dev_kfree_skb(skb); read_unlock_irqrestore(&bond->lock, flags); return 0; } slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; while ( (slave_no > 0) && (slave != (slave_t *)bond) ) { slave = slave->prev; slave_no--; } start_at = slave; do { if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { skb->dev = slave->dev; skb->priority = 1; dev_queue_xmit(skb); read_unlock_irqrestore(&bond->lock, flags); return 0; } } while ((slave = slave->next) != start_at); /* no suitable interface, frame not sent */ dev_kfree_skb(skb); read_unlock_irqrestore(&bond->lock, flags); return 0;}/* * in active-backup mode, we know that bond->current_slave is always valid if * the bond has a usable interface. */static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev){ struct bonding *bond = (struct bonding *) dev->priv; unsigned long flags; int ret; if (!IS_UP(dev)) { /* bond down */ dev_kfree_skb(skb); return 0; } /* if we are sending arp packets, try to at least identify our own ip address */ if ( (arp_interval > 0) && (my_ip==0) && (skb->protocol == __constant_htons(ETH_P_ARP) ) ) { char *the_ip = (((char *)skb->data)) + sizeof(struct ethhdr) + sizeof(struct arphdr) + ETH_ALEN; memcpy(&my_ip, the_ip, 4); } /* if we are sending arp packets and don't know the target hw address, save it so we don't need to use a broadcast address */ if ( (arp_interval > 0) && (arp_target_hw_addr==NULL) && (skb->protocol == __constant_htons(ETH_P_IP) ) ) { struct ethhdr *eth_hdr = (struct ethhdr *) (((char *)skb->data)); arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL); memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN); } read_lock_irqsave(&bond->lock, flags); read_lock(&bond->ptrlock); if (bond->current_slave != NULL) { /* one usable interface */ skb->dev = bond->current_slave->dev; read_unlock(&bond->ptrlock); skb->priority = 1; ret = dev_queue_xmit(skb); read_unlock_irqrestore(&bond->lock, flags); return 0; } else { read_unlock(&bond->ptrlock); } /* no suitable interface, frame not sent */#ifdef BONDING_DEBUG printk(KERN_INFO "There was no suitable interface, so we don't transmit\n");#endif dev_kfree_skb(skb); read_unlock_irqrestore(&bond->lock, flags); return 0;}static struct net_device_stats *bond_get_stats(struct net_device *dev){ bonding_t *bond = dev->priv; struct net_device_stats *stats = bond->stats, *sstats; slave_t *slave; unsigned long flags; memset(bond->stats, 0, sizeof(struct net_device_stats)); read_lock_irqsave(&bond->lock, flags); for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) { sstats = slave->dev->get_stats(slave->dev); stats->rx_packets += sstats->rx_packets; stats->rx_bytes += sstats->rx_bytes; stats->rx_errors += sstats->rx_errors; stats->rx_dropped += sstats->rx_dropped; stats->tx_packets += sstats->tx_packets; stats->tx_bytes += sstats->tx_bytes; stats->tx_errors += sstats->tx_errors; stats->tx_dropped += sstats->tx_dropped; stats->multicast += sstats->multicast; stats->collisions += sstats->collisions; stats->rx_length_errors += sstats->rx_length_errors; stats->rx_over_errors += sstats->rx_over_errors; stats->rx_crc_errors += sstats->rx_crc_errors; stats->rx_frame_errors += sstats->rx_frame_errors; stats->rx_fifo_errors += sstats->rx_fifo_errors; stats->rx_missed_errors += sstats->rx_missed_errors; stats->tx_aborted_errors += sstats->tx_aborted_errors; stats->tx_carrier_errors += sstats->tx_carrier_errors; stats->tx_fifo_errors += sstats->tx_fifo_errors; stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; stats->tx_window_errors += sstats->tx_window_errors; } read_unlock_irqrestore(&bond->lock, flags); return stats;}static int bond_get_info(char *buf, char **start, off_t offset, int length){ bonding_t *bond = these_bonds; int len = 0; off_t begin = 0; u16 link; slave_t *slave = NULL; unsigned long flags; while (bond != NULL) { /* * This function locks the mutex, so we can't lock it until * afterwards */ link = bond_check_mii_link(bond); len += sprintf(buf + len, "Bonding Mode: "); len += sprintf(buf + len, "%s\n", mode ? "active-backup" : "load balancing"); if (mode == BOND_MODE_ACTIVEBACKUP) { read_lock_irqsave(&bond->lock, flags); read_lock(&bond->ptrlock); if (bond->current_slave != NULL) { len += sprintf(buf + len, "Currently Active Slave: %s\n", bond->current_slave->dev->name); } read_unlock(&bond->ptrlock); read_unlock_irqrestore(&bond->lock, flags); } len += sprintf(buf + len, "MII Status: "); len += sprintf(buf + len, link == MII_LINK_READY ? "up\n" : "down\n"); len += sprintf(buf + len, "MII Polling Interval (ms): %d\n", miimon); len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay); len += sprintf(buf + len, "Down Delay (ms): %d\n", downdelay); read_lock_irqsave(&bond->lock, flags); for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { len += sprintf(buf + len, "\nSlave Interface: %s\n", slave->dev->name); len += sprintf(buf + len, "MII Status: "); len += sprintf(buf + len, slave->link == BOND_LINK_UP ? "up\n" : "down\n"); len += sprintf(buf + len, "Link Failure Count: %d\n", slave->link_failure_count); } read_unlock_irqrestore(&bond->lock, flags); /* * Figure out the calcs for the /proc/net interface */ *start = buf + (offset - begin); len -= (offset - begin); if (len > length) { len = length; } if (len < 0) { len = 0; } bond = bond->next_bond; } return len;}static int bond_event(struct notifier_block *this, unsigned long event, void *ptr){ struct bonding *this_bond=(struct bonding *)these_bonds; struct bonding *last_bond; struct net_device *event_dev = (struct net_device *)ptr; /* while there are bonds configured */ while (this_bond != NULL) { if (this_bond == event_dev->priv ) { switch (event) { case NETDEV_UNREGISTER: /* * remove this bond from a linked list of * bonds */ if (this_bond == these_bonds) { these_bonds = this_bond->next_bond; } else { for (last_bond = these_bonds; last_bond != NULL; last_bond = last_bond->next_bond) { if (last_bond->next_bond == this_bond) { last_bond->next_bond = this_bond->next_bond; } } } return NOTIFY_DONE; default: return NOTIFY_DONE; } } else if (this_bond->device == event_dev->master) { switch (event) { case NETDEV_UNREGISTER: bond_release(this_bond->device, event_dev); break; } return NOTIFY_DONE; } this_bond = this_bond->next_bond; } return NOTIFY_DONE;}static struct notifier_block bond_netdev_notifier={ bond_event, NULL, 0};static int __init bond_init(struct net_device *dev){ bonding_t *bond, *this_bond, *last_bond;#ifdef BONDING_DEBUG printk (KERN_INFO "Begin bond_init for %s\n", dev->name);#endif bond = kmalloc(sizeof(struct bonding), GFP_KERNEL); if (bond == NULL) { return -ENOMEM; } memset(bond, 0, sizeof(struct bonding)); /* initialize rwlocks */ rwlock_init(&bond->lock); rwlock_init(&bond->ptrlock); bond->stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (bond->stats == NULL) { kfree(bond); return -ENOMEM; } memset(bond->stats, 0, sizeof(struct net_device_stats)); bond->next = bond->prev = (slave_t *)bond; bond->current_slave = NULL; bond->device = dev; dev->priv = bond; /* Initialize the device structure. */ if (mode == BOND_MODE_ACTIVEBACKUP) { dev->hard_start_xmit = bond_xmit_activebackup; } else if (mode == BOND_MODE_ROUNDROBIN) { dev->hard_start_xmit = bond_xmit_roundrobin; } else if (mode == BOND_MODE_XOR) { dev->hard_start_xmit = bond_xmit_xor; } else { printk(KERN_ERR "Unknown bonding mode %d\n", mode); kfree(bond->stats); kfree(bond); return -EINVAL; } dev->get_stats = bond_get_stats; dev->open = bond_open; dev->stop = bond_close; dev->set_multicast_list = set_multicast_list; dev->do_ioctl = bond_ioctl; /* * Fill in the fields of the device structure with ethernet-generic * values. */ ether_setup(dev); dev->tx_queue_len = 0; dev->flags |= IFF_MASTER|IFF_MULTICAST;#ifdef CONFIG_NET_FASTROUTE dev->accept_fastpath = bond_accept_fastpath;#endif printk(KERN_INFO "%s registered with", dev->name); if (miimon > 0) { printk(" MII link monitoring set to %d ms", miimon); updelay /= miimon; downdelay /= miimon; } else { printk("out MII link monitoring"); } printk(", in %s mode.\n",mode?"active-backup":"bonding");#ifdef CONFIG_PROC_FS bond->bond_proc_dir = proc_mkdir(dev->name, proc_net); if (bond->bond_proc_dir == NULL) { printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n", dev->name, dev->name); kfree(bond->stats); kfree(bond); return -ENOMEM; } bond->bond_proc_info_file = create_proc_info_entry("info", 0, bond->bond_proc_dir, bond_get_info); if (bond->bond_proc_info_file == NULL) { printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n", dev->name, dev->name); remove_proc_entry(dev->name, proc_net); kfree(bond->stats); kfree(bond); return -ENOMEM; }#endif /* CONFIG_PROC_FS */ if (first_pass == 1) { these_bonds = bond; register_netdevice_notifier(&bond_netdev_notifier); first_pass = 0; } else { last_bond = these_bonds; this_bond = these_bonds->next_bond; while (this_bond != NULL) { last_bond = this_bond; this_bond = this_bond->next_bond; } last_bond->next_bond = bond; } return 0;}/*static int __init bond_probe(struct net_device *dev){ bond_init(dev); return 0;} */static int __init bonding_init(void){ int no; int err; /* Find a name for this unit */ static struct net_device *dev_bond = NULL; dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), GFP_KERNEL); if (dev_bond == NULL) { return -ENOMEM; } memset(dev_bonds, 0, max_bonds*sizeof(struct net_device)); if (arp_ip_target) { if (my_inet_aton(arp_ip_target, &arp_target) == 0) { arp_interval = 0; } } for (no = 0; no < max_bonds; no++) { dev_bond->init = bond_init; err = dev_alloc_name(dev_bond,"bond%d"); if (err < 0) { kfree(dev_bonds); return err; } SET_MODULE_OWNER(dev_bond); if (register_netdev(dev_bond) != 0) { kfree(dev_bonds); return -EIO; } dev_bond++; } return 0;}static void __exit bonding_exit(void){ struct net_device *dev_bond = dev_bonds; struct bonding *bond; int no; unregister_netdevice_notifier(&bond_netdev_notifier); for (no = 0; no < max_bonds; no++) {#ifdef CONFIG_PROC_FS bond = (struct bonding *) dev_bond->priv; remove_proc_entry("info", bond->bond_proc_dir); remove_proc_entry(dev_bond->name, proc_net);#endif unregister_netdev(dev_bond); kfree(bond->stats); kfree(dev_bond->priv); dev_bond->priv = NULL; dev_bond++; } kfree(dev_bonds);}module_init(bonding_init);module_exit(bonding_exit);MODULE_LICENSE("GPL");/* * Local variables: * c-indent-level: 8 * c-basic-offset: 8 * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -