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

📄 directiplookup.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
字号:
// -*- c-basic-offset: 4 -*-/* * directiplookup.{cc,hh} -- lookup for output port and next-hop gateway  * in one to max. two DRAM accesses with potential CPU cache / TLB misses * Marko Zec * * Copyright (c) 2005 International Computer Science Institute * Copyright (c) 2005 University of Zagreb * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "directiplookup.hh"#include <click/ipaddress.hh>#include <click/straccum.hh>#include <click/router.hh>#include <click/error.hh>CLICK_DECLSDirectIPLookup::DirectIPLookup(){    add_input();    flush_table();}DirectIPLookup::~DirectIPLookup(){}voidDirectIPLookup::notify_noutputs(int n){    set_noutputs(n);}intDirectIPLookup::initialize(ErrorHandler *){    return 0;}voidDirectIPLookup::push(int, Packet *p){    IPAddress gw;    int port = DirectIPLookup::lookup_route(p->dst_ip_anno(), gw);    if (port >= 0) {        if (gw)            p->set_dst_ip_anno(gw);        output(port).push(p);    } else        p->kill();}intDirectIPLookup::lookup_route(IPAddress dest, IPAddress &gw) const{    uint32_t ip_addr = ntohl(dest.addr());    uint16_t vport_i = _tbl_0_23[ip_addr >> 8];    if (vport_i & 0x8000)        vport_i = _tbl_24_31[((vport_i & 0x7fff) << 8) | (ip_addr & 0xff)];    gw = _vport[vport_i].gw;    return _vport[vport_i].port;}intDirectIPLookup::add_route(const IPRoute& route, bool allow_replace, IPRoute* old_route, ErrorHandler *errh){    uint32_t start, end, i, j, sec_i, sec_start, sec_end, hash;    uint32_t prefix = ntohl(route.addr.addr());    uint32_t plen = route.prefix_len();    int rt_i = find_entry(prefix, plen);    uint16_t vport_i;    if (rt_i >= 0) {	// Attempt to replace an existing route.	// Save the old route if requested so that a rollback can be performed	if ((rt_i != 0 || (rt_i == 0 && _vport[0].port != DISCARD_PORT)) &&	    old_route)	    *old_route = IPRoute(IPAddress(htonl(_rtable[rt_i].prefix)),				 IPAddress::make_prefix(_rtable[rt_i].plen),				 _vport[_rtable[rt_i].vport].gw,				 _vport[_rtable[rt_i].vport].port);	if (rt_i == 0) {	    // We actually only update the vport entry for the default route	    if (_vport[0].port != DISCARD_PORT && !allow_replace)		return -EEXIST;	    _vport[0].gw = route.gw;	    _vport[0].port = route.port;	    return 0;	}	// Check if we allow for atomic route replacements at all	if (!allow_replace)	    return -EEXIST;	vport_unref(_rtable[rt_i].vport);    } else {	// Allocate a new _rtable[] entry	if (_rt_empty_head >= 0) {	    rt_i = _rt_empty_head;	    _rt_empty_head = _rtable[_rt_empty_head].ll_next;	} else {	    if (_rt_size == RT_SIZE_MAX)		return -ENOMEM;	    if (plen > 24 && (_sec_t_empty_head & 0x8000) &&	       _sec_t_size == SEC_SIZE_MAX << 8)		return -ENOMEM;	    if (_vport_empty_head == -1 && _vport_t_size == VPORTS_MAX)		return -ENOMEM;	    rt_i = _rt_size++;	}	_rtable[rt_i].prefix = prefix;	// in host-order format	_rtable[rt_i].plen = plen;	// Insert the new entry in our hashtable	hash = prefix_hash(prefix, plen);	_rtable[rt_i].ll_prev = -1;	_rtable[rt_i].ll_next = _rt_hashtbl[hash];	if (_rt_hashtbl[hash] >= 0)	    _rtable[_rt_hashtbl[hash]].ll_prev = rt_i;	_rt_hashtbl[hash] = rt_i;    }       vport_i = vport_ref(route.gw, route.port);    _rtable[rt_i].vport = vport_i;    start = prefix >> 8;    if (plen >= 24)	end = start + 1;    else	end = start + (1 << (24 - plen));    for (i = start; i < end; i++) {	if (_tbl_0_23[i] & 0x8000) {	    // Entries with plen > 24 already there in _tbl_24_31[]!	    sec_i = (_tbl_0_23[i] & 0x7fff) << 8;	    if (plen > 24) {		sec_start = prefix & 0xFF;		sec_end = sec_start + (1 << (32 - plen));	    } else {		sec_start = 0;		sec_end = 256;	    }	    for (j = sec_i + sec_start; j < sec_i + sec_end; j++) {		if (plen > _tbl_24_31_plen[j]) {		    _tbl_24_31[j] = vport_i;		    _tbl_24_31_plen[j] = plen;		} else if (plen < _tbl_24_31_plen[j]) {		    // Skip a sequence of more-specific entries		    if (_tbl_24_31_plen[j] > 24) {			j |= 0x000000ff >> (_tbl_24_31_plen[j] - 24);		    } else {			i |= 0x00ffffff >> _tbl_24_31_plen[j];			break;		    }		} else if (allow_replace) {		    _tbl_24_31[j] = vport_i;		} else {		    // plen == _tbl_24_31_plen[j] -> damn!		    return errh->error("BUG: _tbl_24_31[%08X] collision", j);		}	    }	} else {	    if (plen > _tbl_0_23_plen[i]) {		if (plen > 24) {		    // Allocate a new _tbl_24_31[] entry and populate it		    if ((_sec_t_empty_head & 0x8000) == 0) {			sec_i = _sec_t_empty_head << 8;			_sec_t_empty_head = _tbl_24_31[sec_i];		    } else {			sec_i = _sec_t_size;			_sec_t_size += 256;		    }		    sec_start = prefix & 0xFF;		    sec_end = sec_start + (1 << (32 - plen));		    for (j = 0; j < 256; j++) {			if (j >= sec_start && j < sec_end) {			    _tbl_24_31[sec_i + j] = vport_i;			    _tbl_24_31_plen[sec_i + j] = plen;			} else {			    _tbl_24_31[sec_i + j] = _tbl_0_23[i];			    _tbl_24_31_plen[sec_i + j] = _tbl_0_23_plen[i];			}		    }		    _tbl_0_23[i] = (sec_i >> 8) | 0x8000;		} else {		    _tbl_0_23[i] = vport_i;		    _tbl_0_23_plen[i] = plen;		}	    } else if (plen < _tbl_0_23_plen[i]) {		// Skip a sequence of more-specific entries		i |= 0x00ffffff >> _tbl_0_23_plen[i];	    } else if (allow_replace) {		_tbl_0_23[i] = vport_i;	    } else {		// plen == _tbl_0_23_plen[i] - must never happen!!!		return errh->error("BUG: _tbl_0_23[%08X] collision", i);	    }	}    }    return 0;}intDirectIPLookup::remove_route(const IPRoute& route, IPRoute* old_route, ErrorHandler *errh){    uint32_t prefix = ntohl(route.addr.addr());    uint32_t plen = route.prefix_len();    int rt_i = find_entry(prefix, plen);    IPRoute found_route;    if (rt_i < 0 || (rt_i == 0 && _vport[0].port == DISCARD_PORT))	return -ENOENT;    found_route = IPRoute(IPAddress(htonl(_rtable[rt_i].prefix)),			  IPAddress::make_prefix(_rtable[rt_i].plen),			  _vport[_rtable[rt_i].vport].gw,			  _vport[_rtable[rt_i].vport].port);    if (!route.match(found_route))	return -ENOENT;    if (old_route)	*old_route = found_route;    if (plen == 0) {	// Default route is a special case.  We never remove it from lookup	// tables, but instead only point it to the "discard port".	if (rt_i > 0)	// Must never happen, checking it just in case...	    return errh->error("BUG: default route rt_i=%d, should be 0", rt_i);	_vport[0].port = DISCARD_PORT;    } else {	uint32_t start, end, i, j, sec_i, sec_start, sec_end;	int newent = -1;	int newmask, prev, next;	vport_unref(_rtable[rt_i].vport);	// Prune our entry from the prefix/len hashtable	prev = _rtable[rt_i].ll_prev;	next = _rtable[rt_i].ll_next;	if (prev >= 0)	    _rtable[prev].ll_next = next;	else	    _rt_hashtbl[prefix_hash(prefix, plen)] = next;	if (next >= 0)	    _rtable[next].ll_prev = prev;	// Add entry to the list of empty _rtable entries	_rtable[rt_i].ll_next = _rt_empty_head;	_rt_empty_head = rt_i;	// Find an entry covering current prefix/len with the longest prefix.	for (newmask = plen - 1 ; newmask >= 0 ; newmask--)	    if (newmask == 0) {		newent = 0;	// rtable[0] is always the default route		break;	    } else {		newent = find_entry(prefix & (0xffffffff << (32 - newmask)),				    newmask);		if (newent > 0)		    break;	    }	// Replace prefix/plen with newent/mask in lookup tables	start = prefix >> 8;	if (plen >= 24)	    end = start + 1;	else	    end = start + (1 << (24 - plen));	for (i = start; i < end; i++) {	    if (_tbl_0_23[i] & 0x8000) {		sec_i = (_tbl_0_23[i] & 0x7fff) << 8;		if (plen > 24) {		    sec_start = prefix & 0xFF;		    sec_end = sec_start + (1 << (32 - plen));		} else {		    sec_start = 0;	    	    sec_end = 256;		}		for (j = sec_i + sec_start; j < sec_i + sec_end; j++) {		    if (plen == _tbl_24_31_plen[j]) {			_tbl_24_31[j] = _rtable[newent].vport;			_tbl_24_31_plen[j] = newmask;		    } else if (plen < _tbl_24_31_plen[j]) {			// Skip a sequence of more-specific entries			if (_tbl_24_31_plen[j] > 24) {			    j |= 0x000000ff >> (_tbl_24_31_plen[j] - 24);			} else {			    i |= 0x00ffffff >> _tbl_24_31_plen[j];			    break;			}		    } else {			// plen > _tbl_24_31_plen[j] -> damn!			return			  errh->error("BUG: _tbl_24_31[%08X] inconsistency", j);		    }		}		// Check if we can prune the entire secondary table range?		for (j = sec_i ; j < sec_i + 255; j++)		    if (_tbl_24_31_plen[j] != _tbl_24_31_plen[j+1])			break;		if (j == sec_i + 255) {		    // Yup, adjust entries in primary tables...		    _tbl_0_23[i] = _tbl_24_31[sec_i];		    _tbl_0_23_plen[i] = _tbl_24_31_plen[sec_i];		    // ... and free up the entry (adding it to free space list)		    _tbl_24_31[sec_i] = _sec_t_empty_head;	    	    _sec_t_empty_head = sec_i >> 8;		}	    } else {		if (plen == _tbl_0_23_plen[i]) {		    _tbl_0_23[i] = _rtable[newent].vport;		    _tbl_0_23_plen[i] = newmask;		} else if (plen < _tbl_0_23_plen[i]) {		    // Skip a sequence of more-specific entries		    i |= 0x00ffffff >> _tbl_0_23_plen[i];		}	    }	}    }    return 0;}intDirectIPLookup::flush_handler(const String &, Element *e, void *,				ErrorHandler *){    DirectIPLookup *t = static_cast<DirectIPLookup *>(e);    t->flush_table();    return 0;}StringDirectIPLookup::dump_routes(){    StringAccum sa;    for (uint32_t i = 0; i < PREF_HASHSIZE; i++)	for (int rt_i = _rt_hashtbl[i]; rt_i >= 0 ; rt_i = _rtable[rt_i].ll_next) {	    const CleartextEntry& rt = _rtable[rt_i];	    if (_vport[rt.vport].port != -1) {		IPRoute route = IPRoute(IPAddress(htonl(rt.prefix)), IPAddress::make_prefix(rt.plen), _vport[rt.vport].gw, _vport[rt.vport].port);		route.unparse(sa, true) << '\n';	    }	}    return sa.take_string();}voidDirectIPLookup::add_handlers(){    // Must keep those in sync with iproutetable.cc!  We need to have our    // own add_handlers() in order to support the flush() operation.    add_write_handler("add", add_route_handler, 0);    add_write_handler("set", add_route_handler, (void*) 1);    add_write_handler("remove", remove_route_handler, 0);    add_write_handler("ctrl", ctrl_handler, 0);    add_read_handler("table", table_handler, 0);    set_handler("lookup", Handler::OP_READ | Handler::READ_PARAM | Handler::ONE_HOOK, lookup_handler);    add_write_handler("flush", flush_handler, 0);}intDirectIPLookup::find_entry(uint32_t prefix, uint32_t plen) const{    int rt_i;    for (rt_i = _rt_hashtbl[prefix_hash(prefix,plen)]; rt_i >= 0 ;      rt_i = _rtable[rt_i].ll_next)	if (_rtable[rt_i].prefix == prefix && _rtable[rt_i].plen == plen)	    return rt_i;    return -1;}inline uint32_tDirectIPLookup::prefix_hash(uint32_t prefix, uint32_t len) const{    // An arbitrary hash function - it'd better be good...    uint32_t hash = prefix ^ (len << 5) ^ (prefix >> (len >> 2)) - len;    hash ^= (hash >> 23) ^ ((hash >> 15) * len) ^ ((prefix >> 17) * 53);    hash -= (prefix >> 3) ^ ((hash >> len) * 7) ^ ((hash >> 11) * 103);    hash =  (hash ^ (hash >> 17)) & (PREF_HASHSIZE - 1);    return hash;};voidDirectIPLookup::flush_table(){    memset(_rt_hashtbl, -1, sizeof(_rt_hashtbl));    // _vport[0] is our "discard" port    _vport_head = 0;    _vport[0].ll_prev = -1;    _vport[0].ll_next = -1;    _vport[0].refcount = 1;		// _rtable[0] will point to _vport[0]    _vport[0].gw = IPAddress(0);    _vport[0].port = DISCARD_PORT;    _vport_t_size = 1;    _vport_empty_head = -1;    // _rtable[0] is the default route entry    _rt_hashtbl[prefix_hash(0,0)] = 0;    _rtable[0].ll_prev = -1;    _rtable[0].ll_next = -1;    _rtable[0].prefix = 0;    _rtable[0].plen = 0;    _rtable[0].vport = 0;    _rt_size = 1;    _rt_empty_head = -1;    // Bzeroed lookup tables resolve 0.0.0.0/0 to _vport[0]    memset(&_tbl_0_23, 0, sizeof(_tbl_0_23));    memset(&_tbl_24_31, 0, sizeof(_tbl_24_31));    // Prefix len helper tables also have to be cleared    memset(&_tbl_0_23_plen, 0, sizeof(_tbl_0_23_plen));    memset(&_tbl_24_31_plen, 0, sizeof(_tbl_24_31_plen));    _sec_t_size = 0;    _sec_t_empty_head = 0x8000;}uint16_tDirectIPLookup::vport_ref(IPAddress gw, int16_t port){    int16_t vport_i;    // Search for an existing entry    for (vport_i = _vport_head; vport_i >= 0; vport_i = _vport[vport_i].ll_next)	if (gw == _vport[vport_i].gw && port == _vport[vport_i].port)	    break;    if (vport_i >= 0)	_vport[vport_i].refcount++;    else {	// Create a new vport entry	if (_vport_empty_head >= 0) {	    vport_i = _vport_empty_head;	    _vport_empty_head = _vport[vport_i].ll_next;	} else	    vport_i = _vport_t_size++;	_vport[vport_i].refcount = 1;	_vport[vport_i].gw = gw;	_vport[vport_i].port = port;	// Add the entry to the vport linked list	_vport[vport_i].ll_prev = -1;	_vport[vport_i].ll_next = _vport_head;	if (_vport_head >= 0)	    _vport[_vport_head].ll_prev = vport_i;	_vport_head = vport_i;    }    return vport_i;}voidDirectIPLookup::vport_unref(uint16_t vport_i){    if (--_vport[vport_i].refcount == 0) {	int16_t prev, next;	// Prune our entry from the vport list	prev = _vport[vport_i].ll_prev;	next = _vport[vport_i].ll_next;	if (prev >= 0)	    _vport[prev].ll_next = next;	else	    _vport_head = next;	if (next >= 0)	    _vport[next].ll_prev = prev;	// Add the entry to empty vports list	_vport[vport_i].ll_next = _vport_empty_head;	_vport_empty_head = vport_i;    }}CLICK_ENDDECLSELEMENT_REQUIRES(IPRouteTable userlevel|bsdmodule)EXPORT_ELEMENT(DirectIPLookup)

⌨️ 快捷键说明

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