📄 rangeiplookup.cc
字号:
// -*- c-basic-offset: 4 -*-/* * rangeiplookup.{cc,hh} -- binary search for output port and next-hop gateway * in a very compact sorted array, aiming for high CPU cache hit ratios * 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 "rangeiplookup.hh"#include <click/ipaddress.hh>#include <click/straccum.hh>#include <click/router.hh>#include <click/error.hh>CLICK_DECLSRangeIPLookup::RangeIPLookup() : _range_base((uint32_t *) CLICK_LALLOC((1 << KICKSTART_BITS) * sizeof(uint32_t))), _range_len((uint32_t *) CLICK_LALLOC((1 << KICKSTART_BITS) * sizeof(uint32_t))), _range_t((uint32_t *) CLICK_LALLOC(RANGES_MAX * sizeof(uint32_t))), _active(false){}RangeIPLookup::~RangeIPLookup(){ CLICK_LFREE(_range_base, (1 << KICKSTART_BITS) * sizeof(uint32_t)); CLICK_LFREE(_range_len, (1 << KICKSTART_BITS) * sizeof(uint32_t)); CLICK_LFREE(_range_t, RANGES_MAX * sizeof(uint32_t));}intRangeIPLookup::configure(Vector<String> &conf, ErrorHandler *errh){ int r; if ((r = _helper.initialize()) < 0) return r; flush_table(); return IPRouteTable::configure(conf, errh);}intRangeIPLookup::initialize(ErrorHandler *){ expand(); _active = true; return 0;}voidRangeIPLookup::cleanup(CleanupStage){ _helper.cleanup();}voidRangeIPLookup::push(int, Packet *p){ IPAddress gw; int port = lookup_route(p->dst_ip_anno(), gw);#ifdef RANGEIPLOOKUP_VERBOSE // Consistency check - does directiplookup yied the same result? IPAddress gw1; int port1 = _helper.lookup_route(p->dst_ip_anno(), gw1); if (port != port1 || gw != gw1) click_chatter("RangeIPLookup: consistency check failed!");#endif if (port >= 0) { if (gw) p->set_dst_ip_anno(gw); output(port).push(p); } else p->kill();}intRangeIPLookup::lookup_route(IPAddress dest, IPAddress &gw) const{ uint32_t ip_addr = ntohl(dest.addr()); uint32_t lowerbound, upperbound, middle; uint32_t i = ip_addr >> RANGE_SHIFT; // kickstart table index = MS bits uint16_t vport_i; lowerbound = _range_base[i]; upperbound = lowerbound + _range_len[i]; i = ip_addr & RANGE_MASK; // Compare only masked LS bits // Binary search for a matching range while (upperbound > lowerbound) { middle = (upperbound + lowerbound) >> 1; if (i < (_range_t[middle] & RANGE_MASK)) upperbound = middle; else if (i < (_range_t[middle + 1] & RANGE_MASK)) { lowerbound = middle; break; } else lowerbound = middle + 1; } // MS bits of the found range contain an index into the output port table vport_i = _range_t[lowerbound] >> RANGE_SHIFT; gw = _helper._vport[vport_i].gw; return _helper._vport[vport_i].port;}voidRangeIPLookup::add_handlers(){ IPRouteTable::add_handlers(); add_write_handler("flush", flush_handler, 0, Handler::BUTTON);}intRangeIPLookup::add_route(const IPRoute& route, bool allow_replace, IPRoute* old_route, ErrorHandler *errh){ int error = _helper.add_route(route, allow_replace, old_route, errh); if (error == 0 && _active) expand(); return error;}intRangeIPLookup::remove_route(const IPRoute& route, IPRoute* old_route, ErrorHandler *errh){ int error = _helper.remove_route(route, old_route, errh); if (error == 0 && _active) expand(); return error;}/* * On each routing table update, we distill the address range based lookup * table from the structures provided by the DirectIPLookup class. * The main cost of this operation is associated with traversing through * 32 + 16 = 48 MBytes of directiplookup tables. We should implement a * more efficient method for updating range-based lookup structures in * the future, which would not depend on huge directiplookup tables. */voidRangeIPLookup::expand(){ uint32_t range_t_index = 0; uint32_t tbl_0_23_index = 0; uint32_t range_base; uint32_t range_len; for (range_base = 0; range_base < (1 << KICKSTART_BITS); range_base++) { uint16_t vport_i, vport_i1; vport_i = 0xffff; // Duh! _range_base[range_base] = range_t_index; for (range_len = 0; tbl_0_23_index < ((range_base + 1) << (24 - KICKSTART_BITS)); tbl_0_23_index++) { if (_helper._tbl_0_23[tbl_0_23_index] & 0x8000) { uint32_t tbl_24_31_index, j; tbl_24_31_index = (_helper._tbl_0_23[tbl_0_23_index] & 0x7fff) << 8; for (j = 0; j < 256; j++) { vport_i1 = _helper._tbl_24_31[tbl_24_31_index + j]; if (vport_i != vport_i1) { vport_i = vport_i1; _range_t[range_t_index] = vport_i << (32 - KICKSTART_BITS) | (((tbl_0_23_index << 8) + j) & (0xffffffff >> KICKSTART_BITS)); range_t_index++; range_len++; } } } else { vport_i1 = _helper._tbl_0_23[tbl_0_23_index]; if (vport_i != vport_i1) { vport_i = vport_i1; _range_t[range_t_index] = vport_i << (32 - KICKSTART_BITS) | ((tbl_0_23_index << 8) & (0xffffffff >> KICKSTART_BITS)); range_t_index++; range_len++; } } } _range_len[range_base] = range_len - 1; }#ifdef RANGEIPLOOKUP_VERBOSE click_chatter("Range expansion done: %d ranges using %d + %d bytes", range_t_index, sizeof(_range_base) + sizeof(_range_len), range_t_index * sizeof(uint32_t));#endif}voidRangeIPLookup::flush_table(){ _helper.flush(); memset(_range_base, 0, sizeof(_range_base)); memset(_range_len, 0, sizeof(_range_len)); memset(_range_t, 0, sizeof(_range_t));}intRangeIPLookup::flush_handler(const String &, Element *e, void *, ErrorHandler *){ RangeIPLookup *t = static_cast<RangeIPLookup *>(e); t->flush_table(); return 0;}StringRangeIPLookup::dump_routes(){ return _helper.dump();}CLICK_ENDDECLSELEMENT_REQUIRES(DirectIPLookup)EXPORT_ELEMENT(RangeIPLookup)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -