⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fromuserdevice.cc

📁 Click is a modular router toolkit. To use it you ll need to know how to compile and install the sof
💻 CC
字号:
/*Programmer: Roman ChertovAll files in this distribution of are Copyright 2005 by the PurdueResearch Foundation of Purdue University. All rights reserved.Redistribution and use in source and binary forms are permittedprovided that this entire copyright notice is duplicated in all suchcopies, and that any documentation, announcements, and other materialsrelated to such distribution and use acknowledge that the software wasdeveloped at Purdue University, West Lafayette, IN.  No charge may bemade for copies, derivations, or distributions of this materialwithout the express written consent of the copyright holder. Neitherthe name of the University nor the name of the author may be used toendorse or promote products derived from this material withoutspecific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS''AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUTLIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FORANY PARTICULAR PURPOSE.*/#include <click/config.h>#include <click/glue.hh>#include <click/error.hh>#include <click/confparse.hh>#include <click/router.hh>#include <click/standard/scheduleinfo.hh>#include <linux/module.h>#include <linux/poll.h>#include <linux/version.h>#include <linux/fs.h>#include <unistd.h>#include<linux/mm.h>#include <click/cxxprotect.h>CLICK_CXX_PROTECT#include <asm/types.h>#include <asm/uaccess.h>#include <linux/ip.h>#include <linux/inetdevice.h>#include <net/route.h>CLICK_CXX_UNPROTECT#include <click/cxxunprotect.h>#include "fromuserdevice.hh"#include <click/hashmap.hh>// need to accomodate a MTU packet as well as the size of the packet in each slotstatic char DEV_NAME[] = "toclick";static int  DEV_MAJOR = 240;static int  DEV_MINOR = 0;static int  DEV_NUM = 0;struct file_operations *FromUserDevice::dev_fops;static void fl_wakeup(Timer *, void *);static FromUserDevice *elem[20] = {0};FromUserDevice::FromUserDevice(){    _size = 0;    _capacity = CAPACITY;    _devname = DEV_NAME;    _buff = 0;    _r_slot = 0;    _w_slot = 0;    _dev_major = DEV_MAJOR;    _dev_minor = DEV_MINOR;    _write_count = 0;    _drop_count = 0;    _pkt_count = 0;    _block_count = 0;    _failed_count = 0;    _exit = false;    _max = 0;}FromUserDevice::~FromUserDevice(){}extern struct file_operations *click_new_file_operations();void FromUserDevice::static_initialize(){    if ((dev_fops = click_new_file_operations())) {	dev_fops->write   = dev_write;	dev_fops->poll    = dev_poll;	dev_fops->open    = dev_open;	dev_fops->release = dev_release;    }}void FromUserDevice::static_cleanup(){    dev_fops = 0;		// proclikefs will free eventually}// open function - called when the "file" /dev/toclick is opened in userspaceint FromUserDevice::dev_open(struct inode *inode, struct file *filp){    int num = MINOR(inode->i_rdev); // low order number    click_chatter("FromUserDevice_open %d\n", num);    if (!elem[num])    {        click_chatter("No FromUserDevice element for this device: %d\n", num);        return -EIO;    }    filp->private_data = elem[num];    return 0;}// close function - called when the "file" /dev/toclikc is closed in userspaceint FromUserDevice::dev_release(struct inode *inode, struct file *filp){    FromUserDevice *elem = (FromUserDevice*)filp->private_data;    if (!elem)    {        click_chatter("Empty private struct!\n");        return -EIO;    }    click_chatter("FromUserDevice_release WriteCounter: %lu\n", elem->_write_count);    return 0;}ssize_t FromUserDevice::dev_write (struct file *filp, const char *buf,                             size_t count, loff_t *ppos){    FromUserDevice *elem = (FromUserDevice*)filp->private_data;    int             err;    WritablePacket *p;    // there is a private field and that doesn't compile in C++ so we can't use DEFINE_WAIT macro    wait_queue_t wq;#include <click/cxxprotect.h>    init_wait(&wq);#include <click/cxxunprotect.h>    ulong        flags;    //click_chatter("FromUserDevice_write %d\n", count);    if (!elem)    {        click_chatter("Empty private struct!\n");        return -EIO;    }    // the incoming buffer is too big    if (count > SLOT_SIZE)    {        spin_lock_irqsave(&elem->_lock, flags);        elem->_drop_count++;        spin_unlock_irqrestore(&elem->_lock, flags);        click_chatter("Incoming buffer is bigger than current slot size\n");        return -EFAULT;    }    // we should make a copy_from_user here and not while we hold the spinlock    p = WritablePacket::make(count);    err = copy_from_user((char*)p->data(), buf, count);    if (err != 0)    {        p->kill();        spin_lock_irqsave(&elem->_lock, flags);        elem->_failed_count++;        spin_unlock_irqrestore(&elem->_lock, flags);        click_chatter("Write Fault");        return -EFAULT;    }    spin_lock_irqsave(&elem->_lock, flags);    while(1)    {        if (elem->_exit)        {            spin_unlock_irqrestore(&elem->_lock, flags);            p->kill();            return -EIO;        }        if (elem->_size >= elem->_capacity)        {            elem->_sleep_proc++;            elem->_block_count++;            spin_unlock_irqrestore(&elem->_lock, flags);            // need to put the process to sleep            //interruptible_sleep_on(&elem->_proc_queue);            prepare_to_wait(&elem->_proc_queue, &wq, TASK_INTERRUPTIBLE);            schedule();            finish_wait(&elem->_proc_queue, &wq);            if (elem->_exit)                return -EIO;            spin_lock_irqsave(&elem->_lock, flags);            elem->_sleep_proc--;        }        else            break; // we are sure that size is not zero so continue now    }    // put the packet pointer into the buffer    elem->_buff[elem->_w_slot] = p;    elem->_w_slot = (elem->_w_slot + 1) % elem->_capacity;    elem->_size++;    elem->_write_count++;    if (elem->_max < elem->_size)        elem->_max = elem->_size;    //click_ip  *ip = (click_ip*)slot->buff;    //click_chatter("%x %x %d %d", ip->ip_src.s_addr, ip->ip_dst.s_addr,    //              ip->ip_v, ip->ip_hl);    spin_unlock_irqrestore(&elem->_lock, flags);    return count;}int FromUserDevice::configure(Vector<String> &conf, ErrorHandler *errh){    int          res;    dev_t        dev;    if (!dev_fops)	return errh->error("file operations missing");    //click_chatter("CONFIGURE\n");    if (cp_va_kparse(conf, this, errh,		     "DEV_MINOR", cpkP+cpkM, cpUnsigned, &_dev_minor,		     "CAPACITY", 0, cpUnsigned, &_capacity,		     cpEnd) < 0)        return -1;    spin_lock_init(&_lock);    if (!(_buff = (WritablePacket**)click_lalloc(_capacity * sizeof(WritablePacket*))))    {        click_chatter("FromUserDevice Failed to alloc %lu slots\n", _capacity);        return -1;    }    _dev_major = DEV_MAJOR;    DEV_NUM++;    if (DEV_NUM == 1)    {        // time to associate the devname with this class        // dynamically allocate the major number with the device        //register the device now. this will register 255 minor numbers        res = register_chrdev(_dev_major, DEV_NAME, dev_fops);        if (res < 0)        {            click_chatter("Failed to Register Dev:%s Major:%d Minor:%d\n",                DEV_NAME, _dev_major, _dev_minor);            click_lfree((char*)_buff, _capacity * sizeof(WritablePacket*));            _buff = 0;            return - EIO;        }    }    elem[_dev_minor] = this;    init_waitqueue_head (&_proc_queue);    click_chatter("Dev:%s Major: %d Minor: %d Size:%d\n", _devname.c_str(), _dev_major, _dev_minor, _size);    return 0;}uint FromUserDevice::dev_poll(struct file *filp, struct poll_table_struct *pt){    FromUserDevice *elem = (FromUserDevice*)filp->private_data;    uint      mask = 0;    ulong     flags;    spin_lock_irqsave(&elem->_lock, flags);    //click_chatter("FromUserDevice_poll\n");    if (elem->_size == elem->_capacity)        mask |= POLLOUT | POLLWRNORM; /* readable */    spin_unlock_irqrestore(&elem->_lock, flags);    return mask;}int FromUserDevice::initialize(ErrorHandler *errh){    click_chatter("FromUserDevice init\n");/*    // don't schedule until we get configured    ScheduleInfo::initialize_task(this, &_task, _buff != 0, errh);#if HAVE_STRIDE_SCHED    // user specifies max number of tickets; we start with default    _max_tickets = _task.tickets();    _task.set_tickets(Task::DEFAULT_TICKETS);#endif*/    return 0;}Packet* FromUserDevice::pull(int){    WritablePacket *p = 0;    ulong           flags;    spin_lock_irqsave(&_lock, flags);    if (_size) {        p = _buff[_r_slot];        _r_slot = (_r_slot + 1) % _capacity;        _size--;        _pkt_count++;    }    spin_unlock_irqrestore(&_lock, flags);    // wake up procs if any are sleeping    wake_up_interruptible(&_proc_queue);    return p;}//cleanupvoid FromUserDevice::cleanup(CleanupStage stage){    ulong flags;    if (stage < CLEANUP_CONFIGURED)        return; // have to quit, as configure was never called    spin_lock_irqsave(&_lock, flags);    DEV_NUM--;    _exit = true;    spin_unlock_irqrestore(&_lock, flags);    if (_buff) {        wake_up_interruptible(&_proc_queue);	while (waitqueue_active(&_proc_queue))	    schedule();        // I guess after this, god knows what will happen to procs that are        // blocked        if (!DEV_NUM)            unregister_chrdev(_dev_major, DEV_NAME);        // now clear out the memory	while (_size) {	    Packet *p = _buff[_r_slot];	    _r_slot = (_r_slot + 1) % _capacity;	    p->kill();	    _size--;	}        click_lfree((char*)_buff, _capacity * sizeof(WritablePacket*));    }}enum { H_COUNT, H_DROPS, H_WRITE_CALLS, H_CAPACITY,       H_SLOT_SIZE, H_SIZE, H_BLOCK, H_FAILED, H_MAX };String FromUserDevice::read_handler(Element *e, void *thunk){    FromUserDevice *c = (FromUserDevice *)e;    switch ((intptr_t)thunk)    {        case H_COUNT:       return String(c->_pkt_count);        case H_FAILED:      return String(c->_failed_count);        case H_SIZE:        return String(c->_size);        case H_BLOCK:       return String(c->_block_count);        case H_DROPS:       return String(c->_drop_count);        case H_WRITE_CALLS: return String(c->_write_count);        case H_CAPACITY:    return String(c->_capacity);        case H_MAX:         return String(c->_max);        default:            return "<error>";    }}void FromUserDevice::add_handlers(){    add_read_handler("count", read_handler, (void *)H_COUNT);    add_read_handler("failed", read_handler, (void *)H_FAILED);    add_read_handler("blocks", read_handler, (void *)H_BLOCK);    add_read_handler("size", read_handler, (void *)H_SIZE);    add_read_handler("drops", read_handler, (void *)H_DROPS);    add_read_handler("writes", read_handler, (void *)H_WRITE_CALLS);    add_read_handler("capacity", read_handler, (void *)H_CAPACITY);    add_read_handler("slot_size", read_handler, (void *)H_SLOT_SIZE);    add_read_handler("max", read_handler, (void *)H_MAX);}ELEMENT_REQUIRES(linuxmodule experimental)EXPORT_ELEMENT(FromUserDevice)ELEMENT_MT_SAFE(FromUserDevice)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -