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

📄 touserdevice.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 2006 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 <click/cxxprotect.h>CLICK_CXX_PROTECT#include <linux/mm.h>#include <linux/module.h>#include <linux/version.h>#include <linux/poll.h>#include <linux/fs.h>#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 "touserdevice.hh"#include <click/hashmap.hh>#include <click/llrpc.h>static char DEV_NAME[] = "touser";static int  DEV_MAJOR = 241;static int  DEV_MINOR = 0;static int  DEV_NUM = 0;struct file_operations *ToUserDevice::dev_fops;static volatile ToUserDevice *elem[20] = {0};ToUserDevice::ToUserDevice() : _task(this){    _exit = false;    _size = 0;    _capacity = default_capacity;    _devname = DEV_NAME;    _q = 0;    _r_slot = 0;    _w_slot = 0;    _dev_major = DEV_MAJOR;    _dev_minor = DEV_MINOR;    _read_count = 0;    _drop_count = 0;    _sleep_proc = 0;    _pkt_count = 0;    _block_count = 0;    _pkt_read_count = 0;    _failed_count = 0;}ToUserDevice::~ToUserDevice(){}extern struct file_operations *click_new_file_operations();void ToUserDevice::static_initialize(){    if ((dev_fops = click_new_file_operations())) {	dev_fops->read    = dev_read;	dev_fops->poll    = dev_poll;	dev_fops->open    = dev_open;	dev_fops->release = dev_release;	dev_fops->ioctl	  = dev_ioctl;    }}void ToUserDevice::static_cleanup(){    dev_fops = 0;		// proclikefs will free eventually}#define GETELEM(filp)		((ToUserDevice *) ((uintptr_t) filp->private_data & ~(uintptr_t) 1))// open function - called when the "file" /dev/toclick is opened in userspaceint ToUserDevice::dev_open(struct inode *inode, struct file *filp){    int num = MINOR(inode->i_rdev); // low order number    click_chatter("**ToUserDevice_open %d\n", num);    if (!elem[num])    {        click_chatter("No ToUserDevice element for this device: %d\n", num);        return -EIO;    }    filp->private_data = (void *) elem[num];    return 0;}// close function - called when the "file" /dev/toclick is closed in userspaceint ToUserDevice::dev_release(struct inode *inode, struct file *filp){    ToUserDevice *elem = GETELEM(filp);    if (!elem) {        click_chatter("Empty private struct!\n");        return -EIO;    }    click_chatter("ToUserDevice_release ReadCounter: %lu\n", elem->_read_count);    return 0;}int ToUserDevice::dev_ioctl(struct inode *inode, struct file *filp,			    unsigned command, unsigned long address){    ToUserDevice *elem = GETELEM(filp);    if (elem->_exit)	return -EIO;    else if (command == CLICK_IOC_TOUSERDEVICE_GET_MULTI)	return ((uintptr_t) filp->private_data) & 1;    else if (command == CLICK_IOC_TOUSERDEVICE_SET_MULTI) {	if ((int) address != 0 && (int) address != 1)            return -EINVAL;	filp->private_data = (void *) ((uintptr_t) elem | (int) address);	return 0;    } else	return -EINVAL;}ssize_t ToUserDevice::dev_read(struct file *filp, char *buff, size_t len, loff_t *ppos){    ToUserDevice *elem = GETELEM(filp);    int multi = ((uintptr_t) filp->private_data) & 1;    int err;    // 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>    spin_lock(&elem->_lock); // LOCK    elem->_read_count++;    while (!elem->_size && !elem->_exit) {	// need to put the process to sleep	elem->_block_count++;	elem->_sleep_proc++;	prepare_to_wait(&elem->_proc_queue, &wq, TASK_INTERRUPTIBLE);	spin_unlock(&elem->_lock); // UNLOCK	schedule();	finish_wait(&elem->_proc_queue, &wq);	if (elem->_exit)	    return -EIO;	spin_lock(&elem->_lock); // LOCK	elem->_sleep_proc--;    }    ssize_t nread = 0;    unsigned nfetched = 0;    while (elem->_size	   && (nfetched == 0 || multi)	   && (nfetched < elem->_max_burst || elem->_max_burst == 0)	   && nread < len	   && !elem->_exit) {	Packet *p = elem->_q[elem->_r_slot];	// user buffer is full	if (nfetched > 0 && nread + sizeof(int) + p->length() > len)	    break;	elem->_r_slot++;	if (elem->_r_slot == elem->_capacity)	    elem->_r_slot = 0;	elem->_size--;	spin_unlock(&elem->_lock);	// unlock as don't need the lock, and can't have a lock and copy_to_user	// copy packet to user level	if (multi) {	    int len = p->length();	    if (copy_to_user(buff + nread, &len, sizeof(int))) {		elem->_failed_count++;		click_chatter("Read Fault");		p->kill();		return -EFAULT;	    }	    nread += sizeof(int);	}	ssize_t to_copy = p->length();	if (to_copy > len - nread)	    to_copy = len - nread;	if (copy_to_user(buff + nread, p->data(), to_copy)) {	    elem->_failed_count++;	    click_chatter("Read Fault");	    p->kill();	    return -EFAULT;	}	nread += to_copy;	// to get int alignment	if (multi && nread % sizeof(int))	    nread += sizeof(int) - nread % sizeof(int);	p->kill();	spin_lock(&elem->_lock);	nfetched++;        elem->_pkt_read_count++;    }    if (nread == 0 && elem->_exit)	nread = -EIO;    spin_unlock(&elem->_lock);    return nread;}uint ToUserDevice::dev_poll(struct file *filp, struct poll_table_struct *pt){    ToUserDevice *elem = GETELEM(filp);    uint    mask = 0;    //click_chatter("ToUserDevice_poll\n");    if (!elem || elem->_exit)	return mask;    poll_wait(filp, &elem->_proc_queue, pt);    spin_lock(&elem->_lock); // LOCK    if (elem->_size)    {        mask |= POLLIN | POLLRDNORM; /* readable */        //click_chatter("ToUserDevice_poll Readable\n");    }    spin_unlock(&elem->_lock); // UNLOCK    return mask;}int ToUserDevice::configure(Vector<String> &conf, ErrorHandler *errh){    int          res;    dev_t        dev;    //click_chatter("CONFIGURE\n");    if (!dev_fops)	return errh->error("file operations missing");    _max_burst = 0;    if (cp_va_kparse(conf, this, errh,		     "DEV_MINOR", cpkP+cpkM, cpUnsigned, &_dev_minor,		     "CAPACITY", 0, cpUnsigned, &_capacity,		     "BURST", 0, cpUnsigned, &_max_burst,		     cpEnd) < 0)        return -1;    spin_lock_init(&_lock); // LOCK INIT    if (!(_q = (Packet **)click_lalloc(_capacity * sizeof(Packet *))))    {        click_chatter("ToUserDevice 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        //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*)_q, _capacity * sizeof(Packet *));            _q = 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;}int ToUserDevice::initialize(ErrorHandler *errh){    click_chatter("**ToUserDevice init\n");    if (input_is_pull(0))    {        ScheduleInfo::initialize_task(this, &_task, errh);        _signal = Notifier::upstream_empty_signal(this, 0, &_task);    }    return 0;}//cleanupvoid ToUserDevice::cleanup(CleanupStage stage){    //click_chatter("cleanup...");    if (stage < CLEANUP_CONFIGURED)        return; // have to quit, as configure was never called    spin_lock(&_lock); // LOCK    DEV_NUM--;    _exit = true; // signal for exit    spin_unlock(&_lock); // UNLOCK    if (_q) {        //click_chatter(" Start ");        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 > 0) {	    _q[_r_slot]->kill();	    _r_slot++;	    if (_r_slot == _capacity)		_r_slot = 0;	    _size--;	}        click_lfree((char*)_q, _capacity * sizeof(Packet *));    }    //click_chatter("cleanup Done. ");}bool ToUserDevice::process(Packet *p){    spin_lock(&_lock);    _pkt_count++;    if (_size >= _capacity) {	_drop_count++;	p->kill();	spin_unlock(&_lock);	return false;    }    _q[_w_slot] = p;    _w_slot++;    if (_w_slot == _capacity)	_w_slot = 0;    _size++;    spin_unlock(&_lock); // UNLOCK    // wake up procs if any are sleeping    wake_up_interruptible(&_proc_queue);    return true;}void ToUserDevice::push(int, Packet *p){    if (p)	process(p);}// something is upstream so we can runbool ToUserDevice::run_task(Task *){    Packet *p = input(0).pull();    int     res;    if (p)        process(p);    else if (!_signal)        return false;    _task.fast_reschedule();    return p != 0;}enum { H_COUNT, H_DROPS, H_READ_CALLS, H_CAPACITY,       H_READ_COUNT, H_SIZE, H_BLOCKS, H_FAILED};String ToUserDevice::read_handler(Element *e, void *thunk){    ToUserDevice *c = (ToUserDevice *)e;    switch ((intptr_t)thunk)    {        case H_COUNT:      return String(c->_pkt_count);        case H_FAILED:      return String(c->_failed_count);        case H_BLOCKS:      return String(c->_block_count);        case H_SIZE:       return String(c->_size);        case H_DROPS:      return String(c->_drop_count);        case H_READ_CALLS: return String(c->_read_count);        case H_READ_COUNT: return String(c->_pkt_read_count);        case H_CAPACITY:   return String(c->_capacity);        default:           return "<error>";    }}void ToUserDevice::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_BLOCKS);    add_read_handler("size", read_handler, (void *)H_SIZE);    add_read_handler("drops", read_handler, (void *)H_DROPS);    add_read_handler("reads", read_handler, (void *)H_READ_CALLS);    add_read_handler("pkt_reads", read_handler, (void *)H_READ_COUNT);    add_read_handler("capacity", read_handler, (void *)H_CAPACITY);    if (input_is_pull(0))        add_task_handlers(&_task);}ELEMENT_REQUIRES(linuxmodule experimental)EXPORT_ELEMENT(ToUserDevice)ELEMENT_MT_SAFE(ToUserDevice)

⌨️ 快捷键说明

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