#include #include #include #include #include #include #include #if CONFIG_MODVERSIONS==1 #define MODVERSIONS #include #endif /** Timer */ struct timer_list estimator_timer; /** Moving average weight */ unsigned interval, time_const; int ewma_log; int idx; /** Function to check bandwidth usage */ void check_bandwidth(unsigned long ptr); /** * init_module: Module init function */ int init_module() { struct net_device *dev; struct bwusage *current_bwusage; /** * Temporarily used to stop the timer after a specific number of times */ unsigned long value; EXPORT_NO_SYMBOLS; /** * Borrowed from iproute2 package (tc/tc_estimator.c) * Following values were obtained by running the estimator for 1 sec * interval and 8 sec time constant of iproute2 package. */ interval = 1000000; /* 1 sec */ time_const = 8000000; /* 8 sec */ idx = 2; ewma_log = 3; /** Could this be true due to previous errors */ if(bwusage_head != NULL) { printk(KERN_INFO "bwestimator: bwusage_head is not NULL\n"); return -1; } bwusage_head = NULL; current_bwusage = NULL; /** Lock the dev_base */ read_lock(&dev_base_lock); /** Lock the bwusage_head */ write_lock(&bwusage_head_lock); for(dev = dev_base; dev != NULL; dev = dev -> next) { struct bwusage *bwusage = kmalloc(sizeof(bwusage), GFP_KERNEL); if(bwusage == NULL) { /** Free allocated memory */ for(bwusage = bwusage_head; bwusage;) { struct bwusage *u = bwusage -> next; kfree(bwusage); bwusage = u; } /** Unlock the bwusage_head */ write_unlock(&bwusage_head_lock); /** Unlock the dev_base */ read_unlock(&dev_base_lock); /** Return error */ return -ENOBUFS; } bwusage -> next = NULL; dev_hold(dev); bwusage -> name = dev -> name; __dev_put(dev); bwusage -> rx_bps = 0; bwusage -> rx_avbps = 0; bwusage -> rx_pps = 0; bwusage -> rx_avpps = 0; bwusage -> rx_bytes = 0; bwusage -> rx_packets = 0; bwusage -> tx_bps = 0; bwusage -> tx_avbps = 0; bwusage -> tx_pps = 0; bwusage -> tx_avpps = 0; bwusage -> tx_bytes = 0; bwusage -> tx_packets = 0; if(bwusage_head == NULL) { bwusage_head = bwusage; } else { current_bwusage -> next = bwusage; } current_bwusage = bwusage; printk(KERN_INFO "bwestimator: Adding %s device (%s), rx_bytes, %lu, rx_packets, %lu, rx_bps, %lu, rx_avbps, %lu, rx_pps, %lu, rx_avpps, %lu\n", dev->name, bwusage -> name, bwusage -> rx_bytes, bwusage -> rx_packets, bwusage -> rx_bps, bwusage -> rx_avbps, bwusage -> rx_pps, bwusage -> rx_avpps); } /** Initialize and setup the timer */ init_timer(&estimator_timer); estimator_timer.function = check_bandwidth; value = 0; estimator_timer.data = (unsigned long) &value; estimator_timer.expires = jiffies + HZ; /* One second */ add_timer(&estimator_timer); /** Unlock the bwusage_head */ write_unlock(&bwusage_head_lock); /** Unlock the dev_base */ read_unlock(&dev_base_lock); printk("<1>bwestimator: Starting bandwidth usage estimation\n"); return 0; } /** * cleanup_module: Module cleanup function */ void cleanup_module() { struct bwusage *current_bwusage; unsigned long flags; /** Lock the bwusage_head */ write_lock(&bwusage_head_lock); /** Delete the timer */ del_timer(&estimator_timer); /** Free allocated memory */ for(current_bwusage = bwusage_head; current_bwusage;) { struct bwusage *u = current_bwusage -> next; printk(KERN_INFO "bwestimator: Deleting %s device\n", current_bwusage -> name ? current_bwusage -> name : "null"); kfree(current_bwusage); current_bwusage = u; } bwusage_head = NULL; /** Unlock the bwusage_head */ write_unlock(&bwusage_head_lock); printk("<1>bwestimator: Stopping bandwidth usage estimation\n"); } /** * check_bandwidth(): Checks the bandwidth usage on interfaces */ void check_bandwidth(unsigned long ptr) { struct net_device *dev; struct bwusage *bwusage; unsigned long *data = (unsigned long *) ptr; unsigned long nbytes, old_nbytes; unsigned long npackets, old_npackets; unsigned long rate; /** Count to print the debug message */ static unsigned count = 0; unsigned long flags; /** Read lock the dev_base */ read_lock(&dev_base_lock); /** Read lock the bwusage_head */ write_lock(&bwusage_head_lock); if(count >= 5) { /** Unlock the bwusage_head */ write_unlock(&bwusage_head_lock); /** Unlock the dev_base */ read_unlock(&dev_base_lock); return; } for(dev = dev_base, bwusage = bwusage_head; dev != NULL && bwusage != NULL; dev = dev -> next, bwusage = bwusage -> next) { struct net_device_stats *stats; dev_hold(dev); stats = (dev -> get_stats ? dev -> get_stats(dev) : (struct net_device_stats *)NULL); if(stats) { #if 0 nbytes = stats -> tx_bytes; npackets = stats -> tx_packets; /** Tx_bps */ rate = (nbytes - bwusage -> tx_bytes) << (7 - idx); bwusage -> tx_bytes = nbytes; bwusage -> tx_avbps += ((long)rate - (long)bwusage ->tx_avbps) >> ewma_log; bwusage -> tx_bps = (bwusage -> tx_avbps + 0xF) >> 5; /** Tx_pps */ rate = (u32) ((npackets - bwusage -> tx_packets) << (12 - idx)); bwusage -> tx_packets = npackets; bwusage -> tx_avpps = (u32) (bwusage -> tx_avpps + (((long)rate - (long)bwusage ->tx_avpps) >> ewma_log)); bwusage -> tx_pps = (u32) ((bwusage -> tx_avpps + 0x1FF) >> 10); /** Rx_bps */ nbytes = stats -> rx_bytes; npackets = stats -> rx_packets; old_nbytes = bwusage -> rx_bytes; old_npackets = bwusage -> rx_packets; rate = (nbytes - bwusage -> rx_bytes) << (7 - idx); bwusage -> rx_bytes = nbytes; bwusage -> rx_avbps += ((long)rate - (long)bwusage ->rx_avbps) >> ewma_log; bwusage -> rx_bps = (bwusage -> rx_avbps + 0xF) >> 5; printk(KERN_INFO "bwestimator: device, %s, nbytes, %lu, npackets, %lu, old_nbytes, %lu, old_npackets, %lu, rate, %lu, rx_avbps, %lu, rx_bps, %lu, idx, %d, ewma_log, %d\n", dev -> name, nbytes, npackets, old_nbytes, old_npackets, rate, bwusage -> rx_avbps, bwusage -> rx_bps, idx, ewma_log); /** Rx_pps */ rate = (u32) ((npackets - bwusage -> rx_packets) << (12 - idx)); bwusage -> rx_packets = npackets; bwusage -> rx_avpps = (u32) (bwusage -> rx_avpps + (((long)rate - (long)bwusage ->rx_avpps) >> ewma_log)); bwusage -> rx_pps = (u32) ((bwusage -> rx_avpps + 0x1FF) >> 10); /* printk(KERN_INFO "bwestimator: Device, %6s, nbytes, %llu, npackets, %lu, rxbps, %lu, rxpps, %lu, txbps, %lu, txpps, %lu\n", bwusage->name, nbytes, npackets, bwusage->rx_bps, bwusage->rx_pps, bwusage->tx_bps, bwusage->tx_pps ); */ #endif } else { printk(KERN_INFO "bwestimator: Device: %6s. No statistics available.\n", dev->name); } __dev_put(dev); } mod_timer(&estimator_timer, jiffies + HZ); printk(KERN_INFO "bwestimator: dev: %s. bwusage: %s.\n", dev ? "non-null" : "null", bwusage ? "non-null" : "null"); count++; /** Unlock the bwusage_head */ write_unlock(&bwusage_head_lock); /** Unlock the dev_base */ read_unlock(&dev_base_lock); return; } MODULE_LICENSE("GPL");