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

📄 arpquerier.cc

📁 Click is a modular router toolkit. To use it you ll need to know how to compile and install the sof
💻 CC
字号:
/* * arpquerier.{cc,hh} -- ARP resolver element * Robert Morris, Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2005 Regents of the University of California * Copyright (c) 2008 Meraki, Inc. * * 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 "arpquerier.hh"#include <clicknet/ether.h>#include <click/etheraddress.hh>#include <click/ipaddress.hh>#include <click/confparse.hh>#include <click/bitvector.hh>#include <click/straccum.hh>#include <click/router.hh>#include <click/error.hh>#include <click/glue.hh>CLICK_DECLSARPQuerier::ARPQuerier()    : _arpt(0), _my_arpt(false){}ARPQuerier::~ARPQuerier(){}void *ARPQuerier::cast(const char *name){    if (strcmp(name, "ARPTable") == 0)	return _arpt;    else if (strcmp(name, "ARPQuerier") == 0)	return this;    else	return Element::cast(name);}intARPQuerier::configure(Vector<String> &conf, ErrorHandler *errh){    uint32_t capacity, entry_capacity;    Timestamp timeout;    bool have_capacity, have_entry_capacity, have_timeout, have_broadcast;    Element *arpt = 0;    if (cp_va_kparse_remove_keywords(conf, this, errh,		"CAPACITY", cpkC, &have_capacity, cpUnsigned, &capacity,		"ENTRY_CAPACITY", cpkC, &have_entry_capacity, cpUnsigned, &entry_capacity,		"TIMEOUT", cpkC, &have_timeout, cpTimestamp, &timeout,		"BROADCAST", cpkC, &have_broadcast, cpIPAddress, &_my_bcast_ip,		"TABLE", 0, cpElement, &arpt,		cpEnd) < 0)	return -1;    if (!arpt) {	Vector<String> subconf;	if (have_capacity)	    subconf.push_back("CAPACITY " + String(capacity));	if (have_entry_capacity)	    subconf.push_back("ENTRY_CAPACITY " + String(entry_capacity));	if (have_timeout)	    subconf.push_back("TIMEOUT " + timeout.unparse());	_arpt = new ARPTable;	_arpt->attach_router(router(), -1);	_arpt->configure(subconf, errh);	_my_arpt = true;    } else if (!(_arpt = static_cast<ARPTable *>(arpt->cast("ARPTable"))))	return errh->error("bad TABLE");    IPAddress my_mask;    if (conf.size() == 1)	conf.push_back(conf[0]);    if (cp_va_kparse(conf, this, errh,		     "IP", cpkP+cpkM, cpIPAddressOrPrefix, &_my_ip, &my_mask,		     "ETH", cpkP+cpkM, cpEthernetAddress, &_my_en,		     cpEnd) < 0)	return -1;    if (!have_broadcast) {	_my_bcast_ip = _my_ip | ~my_mask;	if (_my_bcast_ip == _my_ip)	    _my_bcast_ip = 0xFFFFFFFFU;    }    return 0;}intARPQuerier::live_reconfigure(Vector<String> &conf, ErrorHandler *errh){    uint32_t capacity, entry_capacity;    Timestamp timeout;    bool have_capacity, have_entry_capacity, have_timeout, have_broadcast;    IPAddress my_bcast_ip;    if (cp_va_kparse_remove_keywords(conf, this, errh,		"CAPACITY", cpkC, &have_capacity, cpUnsigned, &capacity,		"ENTRY_CAPACITY", cpkC, &have_entry_capacity, cpUnsigned, &entry_capacity,		"TIMEOUT", cpkC, &have_timeout, cpTimestamp, &timeout,		"BROADCAST", cpkC, &have_broadcast, cpIPAddress, &my_bcast_ip,		"TABLE", 0, cpIgnore,		cpEnd) < 0)	return -1;    IPAddress my_ip, my_mask;    EtherAddress my_en;    if (conf.size() == 1)	conf.push_back(conf[0]);    if (cp_va_kparse(conf, this, errh,		     "IP", cpkP+cpkM, cpIPAddressOrPrefix, &my_ip, &my_mask,		     "ETH", cpkP+cpkM, cpEthernetAddress, &my_en,		     cpEnd) < 0)	return -1;    if (!have_broadcast) {	my_bcast_ip = my_ip | ~my_mask;	if (my_bcast_ip == my_ip)	    my_bcast_ip = 0xFFFFFFFFU;    }    if ((my_ip != _my_ip || my_en != _my_en) && _my_arpt)	_arpt->clear();    _my_ip = my_ip;    _my_en = my_en;    _my_bcast_ip = my_bcast_ip;    if (_my_arpt && have_capacity)	_arpt->set_capacity(capacity);    if (_my_arpt && have_entry_capacity)	_arpt->set_entry_capacity(entry_capacity);    if (_my_arpt && have_timeout)	_arpt->set_timeout(timeout);    return 0;}intARPQuerier::initialize(ErrorHandler *){    _arp_queries = 0;    _drops = 0;    _arp_responses = 0;    return 0;}voidARPQuerier::cleanup(CleanupStage stage){    if (_my_arpt) {	_arpt->cleanup(stage);	delete _arpt;    }}voidARPQuerier::take_state(Element *e, ErrorHandler *errh){    ARPQuerier *arpq = (ARPQuerier *) e->cast("ARPQuerier");    if (!arpq || _my_ip != arpq->_my_ip || _my_en != arpq->_my_en	|| _my_bcast_ip != arpq->_my_bcast_ip)	return;    if (_my_arpt && arpq->_my_arpt)	_arpt->take_state(arpq->_arpt, errh);    _arp_queries = arpq->_arp_queries;    _drops = arpq->_drops;    _arp_responses = arpq->_arp_responses;}voidARPQuerier::send_query_for(Packet *p){    static_assert(Packet::default_headroom >= sizeof(click_ether));    WritablePacket *q = Packet::make(Packet::default_headroom - sizeof(click_ether),				     NULL, sizeof(click_ether) + sizeof(click_ether_arp), 0);    if (!q) {	click_chatter("in arp querier: cannot make packet!");	return;    }    click_ether *e = (click_ether *) q->data();    q->set_ether_header(e);    memset(e->ether_dhost, 0xff, 6);    memcpy(e->ether_shost, _my_en.data(), 6);    e->ether_type = htons(ETHERTYPE_ARP);    click_ether_arp *ea = (click_ether_arp *) (e + 1);    ea->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);    ea->ea_hdr.ar_pro = htons(ETHERTYPE_IP);    ea->ea_hdr.ar_hln = 6;    ea->ea_hdr.ar_pln = 4;    ea->ea_hdr.ar_op = htons(ARPOP_REQUEST);    memcpy(ea->arp_sha, _my_en.data(), 6);    memcpy(ea->arp_spa, _my_ip.data(), 4);    memset(ea->arp_tha, 0, 6);    IPAddress want_ip = p->dst_ip_anno();    memcpy(ea->arp_tpa, want_ip.data(), 4);    q->set_timestamp_anno(p->timestamp_anno());    _arp_queries++;    output(noutputs() - 1).push(q);}/* * If the packet's IP address is in the table, add an ethernet header * and push it out. * Otherwise push out a query packet. * May save the packet in the ARP table for later sending. * May call p->kill(). */voidARPQuerier::handle_ip(Packet *p, bool response){    // delete packet if we are not configured    if (!_my_ip) {	p->kill();	++_drops;	return;    }    // make room for Ethernet header    WritablePacket *q;    if (response) {	assert(!p->shared());	q = p->uniqueify();    } else if (!(q = p->push_mac_header(sizeof(click_ether)))) {	++_drops;	return;    } else	q->ether_header()->ether_type = htons(ETHERTYPE_IP);    IPAddress dst_ip = q->dst_ip_anno();    EtherAddress *dst_eth = reinterpret_cast<EtherAddress *>(q->ether_header()->ether_dhost);    int r;    // Easy case: requires only read lock  retry_read_lock:    r = _arpt->lookup(dst_ip, dst_eth, 60 * CLICK_HZ);    if (r >= 0 && !dst_eth->is_broadcast()) {	memcpy(&q->ether_header()->ether_shost, _my_en.data(), 6);	output(0).push(q);    } else if (dst_ip.addr() == 0xFFFFFFFFU || dst_ip == _my_bcast_ip) {	// Check special IP addresses	*dst_eth = EtherAddress::make_broadcast();	memcpy(&q->ether_header()->ether_shost, _my_en.data(), 6);	output(0).push(q);	r = 0;    } else if (dst_ip.is_multicast()) {	uint8_t *dst_addr = q->ether_header()->ether_dhost;	dst_addr[0] = 0x01;	dst_addr[1] = 0x00;	dst_addr[2] = 0x5E;	uint32_t addr = ntohl(dst_ip.addr());	dst_addr[3] = (addr >> 16) & 0x7F;	dst_addr[4] = addr >> 8;	dst_addr[5] = addr;	memcpy(&q->ether_header()->ether_shost, _my_en.data(), 6);	output(0).push(q);	r = 0;    } else if (!dst_ip) {	static bool zero_warned = false;	if (!zero_warned) {	    click_chatter("%s: would query for 0.0.0.0; missing dest IP addr annotation?", declaration().c_str());	    zero_warned = true;	}	++_drops;	q->kill();	r = 0;    } else {	r = _arpt->append_query(dst_ip, q);	if (r == -EAGAIN)	    goto retry_read_lock;    }    if (r > 0)			// poll	send_query_for(q);}/* * Got an ARP response. * Update our ARP table. * If there was a packet waiting to be sent, return it. */voidARPQuerier::handle_response(Packet *p){    if (p->length() < sizeof(click_ether) + sizeof(click_ether_arp))	return;    ++_arp_responses;    click_ether *ethh = (click_ether *) p->data();    click_ether_arp *arph = (click_ether_arp *) (ethh + 1);    IPAddress ipa = IPAddress(arph->arp_spa);    EtherAddress ena = EtherAddress(arph->arp_sha);    if (ntohs(ethh->ether_type) == ETHERTYPE_ARP	&& ntohs(arph->ea_hdr.ar_hrd) == ARPHRD_ETHER	&& ntohs(arph->ea_hdr.ar_pro) == ETHERTYPE_IP	&& ntohs(arph->ea_hdr.ar_op) == ARPOP_REPLY	&& !ena.is_group()) {	Packet *cached_packet;	_arpt->insert(ipa, ena, &cached_packet);	// Send out packets in the order in which they arrived	while (cached_packet) {	    Packet *next = cached_packet->next();	    handle_ip(cached_packet, true);	    cached_packet = next;	}    }}voidARPQuerier::push(int port, Packet *p){    if (port == 0)	handle_ip(p, false);    else {	handle_response(p);	p->kill();    }}StringARPQuerier::read_handler(Element *e, void *thunk){    ARPQuerier *q = (ARPQuerier *)e;    switch (reinterpret_cast<uintptr_t>(thunk)) {      case h_table:	return q->_arpt->read_handler(q->_arpt, (void *) (uintptr_t) ARPTable::h_table);      case h_stats:	return	    String(q->_drops.value() + q->_arpt->drops()) + " packets killed\n" +	    String(q->_arp_queries.value()) + " ARP queries sent\n";      default:	return String();    }}intARPQuerier::write_handler(const String &str, Element *e, void *thunk, ErrorHandler *errh){    ARPQuerier *q = (ARPQuerier *) e;    switch (reinterpret_cast<uintptr_t>(thunk)) {      case h_insert:	return q->_arpt->write_handler(str, q->_arpt, (void *) (uintptr_t) ARPTable::h_insert, errh);      case h_delete:	return q->_arpt->write_handler(str, q->_arpt, (void *) (uintptr_t) ARPTable::h_delete, errh);      case h_clear:	q->_arp_queries = q->_drops = q->_arp_responses = 0;	q->_arpt->clear();	return 0;      default:	return -1;    }}voidARPQuerier::add_handlers(){    add_read_handler("table", read_handler, h_table);    add_read_handler("stats", read_handler, h_stats);    add_data_handlers("queries", Handler::OP_READ, &_arp_queries);    add_data_handlers("responses", Handler::OP_READ, &_arp_responses);    add_data_handlers("drops", Handler::OP_READ, &_drops);    add_data_handlers("broadcast", Handler::OP_READ | Handler::OP_WRITE, &_my_bcast_ip);    add_data_handlers("ipaddr", Handler::OP_READ | Handler::OP_WRITE, &_my_ip);    add_write_handler("insert", write_handler, h_insert);    add_write_handler("delete", write_handler, h_delete);    add_write_handler("clear", write_handler, h_clear);}CLICK_ENDDECLSEXPORT_ELEMENT(ARPQuerier)ELEMENT_REQUIRES(ARPTable)ELEMENT_MT_SAFE(ARPQuerier)

⌨️ 快捷键说明

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