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

📄 arpquerier.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 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 * * 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/router.hh>#include <click/error.hh>#include <click/glue.hh>CLICK_DECLSARPQuerier::ARPQuerier()    : _age_head(0), _age_tail(0), _expire_timer(expire_hook, this){  add_input(); /* IP packets */  add_input(); /* ether/ARP responses */  add_output();/* ether/IP and ether/ARP queries */  for (int i = 0; i < NMAP; i++)    _map[i] = 0;}ARPQuerier::~ARPQuerier(){}voidARPQuerier::notify_noutputs(int n){  set_noutputs(n < 2 ? 1 : 2);}intARPQuerier::configure(Vector<String> &conf, ErrorHandler *errh){  if (conf.size() == 1)    conf.push_back(conf[0]);  _capacity = 2048;  return cp_va_parse(conf, this, errh,		     cpIPAddress, "IP address", &_my_ip,		     cpEthernetAddress, "Ethernet address", &_my_en,		     cpKeywords,		     "CAPACITY", cpUnsigned, "packet capacity", &_capacity,		     cpEnd);}intARPQuerier::live_reconfigure(Vector<String> &conf, ErrorHandler *errh){  if (configure(conf, errh) < 0) {    // if the configuration failed do nothing and return with a    // failure indication    return -1;  }    // if the new configuration succeeded then wipe out the old arp  // table and reset the queries and pkts_killed counters  clear_map();  _arp_queries = 0;  _drops = 0;  _arp_responses = 0;  return 0;}intARPQuerier::initialize(ErrorHandler *){  _expire_timer.initialize(this);  _expire_timer.schedule_after_ms(EXPIRE_TIMEOUT_MS);  _arp_queries = 0;  _drops = 0;  _arp_responses = 0;  _cache_size = 0;  return 0;}voidARPQuerier::cleanup(CleanupStage){  clear_map();}voidARPQuerier::clear_map(){  // Walk the arp cache table and free   // any stored packets and arp entries.  for (int i = 0; i < NMAP; i++) {    for (ARPEntry *ae = _map[i]; ae; ) {      ARPEntry *n = ae->next;      while (Packet *p = ae->head) {	  ae->head = p->next();	  p->kill();	  _drops++;      }      delete ae;      ae = n;    }    _map[i] = 0;  }  _cache_size = 0;}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)	return;    if (_arp_queries > 0) {	errh->error("late take_state");	return;    }    memcpy(_map, arpq->_map, sizeof(ARPEntry *) * NMAP);    memset(arpq->_map, 0, sizeof(ARPEntry *) * NMAP);    _age_head = arpq->_age_head;    _age_tail = arpq->_age_tail;    _cache_size = arpq->_cache_size;    _arp_queries = arpq->_arp_queries;    _drops = arpq->_drops;    _arp_responses = arpq->_arp_responses;    // Need to change some pprev entries.    for (int i = 0; i < NMAP; i++)	if (_map[i])	    _map[i]->pprev = &_map[i];    if (_age_head)	_age_head->age_pprev = &_age_head;        arpq->_age_head = arpq->_age_tail = 0;    arpq->_cache_size = 0;}voidARPQuerier::expire_hook(Timer *timer, void *thunk){    // Expire any old entries, and make sure there's room for at least one    // packet.    ARPQuerier *arpq = (ARPQuerier *)thunk;    arpq->_lock.acquire_write();    int jiff = click_jiffies();    ARPEntry *ae;    // Delete old entries.    while ((ae = arpq->_age_head) && (jiff - ae->last_response_jiffies) > 300*CLICK_HZ) {	if ((*ae->pprev = ae->next))	    ae->next->pprev = ae->pprev;	if ((arpq->_age_head = ae->age_next))	    arpq->_age_head->age_pprev = &arpq->_age_head;	else	    arpq->_age_tail = 0;		while (Packet *p = ae->head) {	    ae->head = p->next();	    p->kill();	    arpq->_cache_size--;	    arpq->_drops++;	}	delete ae;    }    // Mark entries for polling, and delete packets to make space.    while (ae) {	// Only set polling on timer calls.	if (jiff - ae->last_response_jiffies > 60*CLICK_HZ && timer)	    ae->polling = 1;	else if (arpq->_cache_size < arpq->_capacity)	    break;	while (arpq->_cache_size >= arpq->_capacity && ae->head) {	    Packet *p = ae->head;	    if (!(ae->head = p->next()))		ae->tail = 0;	    p->kill();	    arpq->_cache_size--;	    arpq->_drops++;	}	ae = ae->age_next;    }    if (timer)	timer->schedule_after_ms(EXPIRE_TIMEOUT_MS);    arpq->_lock.release_write();}voidARPQuerier::send_query_for(IPAddress want_ip){  static bool zero_warned = false;    if (!want_ip && !zero_warned) {    click_chatter("%s: querying for 0.0.0.0; missing dest IP addr annotation?", declaration().cc());    zero_warned = true;  }    WritablePacket *q = Packet::make(sizeof(click_ether) + sizeof(click_ether_arp));  if (!q) {    click_chatter("in arp querier: cannot make packet!");    return;  }  memset(q->data(), '\0', q->length());    click_ether *e = (click_ether *) q->data();  q->set_ether_header(e);  memcpy(e->ether_dhost, "\xff\xff\xff\xff\xff\xff", 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_tpa, want_ip.data(), 4);  memcpy(ea->arp_sha, _my_en.data(), 6);  memcpy(ea->arp_spa, _my_ip.data(), 4);  _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){    // delete packet if we are not configured    if (!_my_ip) {	p->kill();	_drops++;	return;    }    IPAddress ipa = p->dst_ip_anno();    int bucket = ip_bucket(ipa);    ARPEntry *ae;    // Easy case: requires only read lock  retry_read_lock:    _lock.acquire_read();    ae = _map[bucket];    while (ae && ae->ip != ipa)	ae = ae->next;    if (ae && ae->ok) {	int was_polling = ae->polling;	ae->polling = 0;	if (WritablePacket *q = p->push_mac_header(sizeof(click_ether))) {	    click_ether *e = q->ether_header();	    memcpy(e->ether_shost, _my_en.data(), 6);	    memcpy(e->ether_dhost, ae->en.data(), 6);	    e->ether_type = htons(ETHERTYPE_IP);	    _lock.release_read();	    output(0).push(q);	} else {	    _drops++;	    _lock.release_read();	}	if (was_polling)	    send_query_for(ipa);	return;    }    _lock.release_read();    // Hard case: requires write lock    // 18.May.2005 -- must expire BEFORE we grab the ae pointer!!    // because expiring might in fact DELETE the ae pointer.    if (_cache_size >= _capacity)	// get some space if necessary	expire_hook(0, this);        _lock.acquire_write();    ae = _map[bucket];    while (ae && ae->ip != ipa)	ae = ae->next;    if (ae && ae->ok) {	_lock.release_write();	goto retry_read_lock;    } else if (ae) {	if (ae->tail)	    ae->tail->set_next(p);	else	    ae->head = p;	ae->tail = p;	p->set_next(0);	_cache_size++;    } else if ((ae = new ARPEntry)) {	ae->ip = ipa;	ae->ok = ae->polling = 0;	ae->last_response_jiffies = click_jiffies() - CLICK_HZ;		ae->head = ae->tail = p;	p->set_next(0);		ae->pprev = &_map[bucket];	if ((ae->next = _map[bucket]))	    ae->next->pprev = &ae->next;	_map[bucket] = ae;		if (_age_tail)	    ae->age_pprev = &_age_tail->age_next;	else	    ae->age_pprev = &_age_head;	_age_tail = *ae->age_pprev = ae;	ae->age_next = 0;		_cache_size++;    } else {	p->kill();	_drops++;	_lock.release_write();	return;    }        _lock.release_write();    // Send a query for any given address at most 10 times a second.    int jiff = click_jiffies();    if ((int) (jiff - ae->last_response_jiffies) >= CLICK_HZ / 10) {	ae->last_response_jiffies = jiff;	send_query_for(ipa);    }}/* * 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()) {    int bucket = ip_bucket(ipa);    _lock.acquire_write();    ARPEntry *ae = _map[bucket];    while (ae && ae->ip != ipa)      ae = ae->next;    if (!ae) {	// XXX would be nice to store an entry for this preemptive response	_lock.release_write();	return;    }        if (ae->ok && ae->en != ena)	click_chatter("ARPQuerier overwriting an entry");    ae->en = ena;    ae->ok = 1;    ae->polling = 0;    ae->last_response_jiffies = click_jiffies();    Packet *cached_packet = ae->head;    ae->head = ae->tail = 0;    if (_age_tail != ae) {	*ae->age_pprev = ae->age_next;	ae->age_next->age_pprev = ae->age_pprev;	ae->age_pprev = &_age_tail->age_next;	ae->age_next = 0;	_age_tail = *ae->age_pprev = ae;    }    _lock.release_write();    // Send out packets in the order in which they arrived    while (cached_packet) {	Packet *next = cached_packet->next();	handle_ip(cached_packet);	cached_packet = next;	_cache_size--;    }  }}voidARPQuerier::push(int port, Packet *p){  if (port == 0)    handle_ip(p);  else {    handle_response(p);    p->kill();  }}StringARPQuerier::read_table(Element *e, void *){  ARPQuerier *q = (ARPQuerier *)e;  String s;  for (int i = 0; i < NMAP; i++)    for (ARPEntry *e = q->_map[i]; e; e = e->next) {      s += e->ip.s() + " " + (e->ok ? "1" : "0") + " " + e->en.s() + "\n";    }  return s;}StringARPQuerier::read_stats(Element *e, void *thunk){  ARPQuerier *q = (ARPQuerier *)e;  switch ((uintptr_t) thunk) {    case 0:      return        String(q->_drops.value()) + " packets killed\n" +        String(q->_arp_queries.value()) + " ARP queries sent\n";    case 1:      return String(q->_arp_queries.value()) + "\n";    case 2:      return String(q->_arp_responses.value()) + "\n";    case 3:      return String(q->_drops.value()) + "\n";    default:      return String();  }}voidARPQuerier::add_handlers(){    add_read_handler("table", read_table, (void *)0);    add_read_handler("stats", read_stats, (void *)0);    add_read_handler("queries", read_stats, (void *)1);    add_read_handler("responses", read_stats, (void *)2);    add_read_handler("drops", read_stats, (void *)3);}CLICK_ENDDECLSEXPORT_ELEMENT(ARPQuerier)ELEMENT_MT_SAFE(ARPQuerier)

⌨️ 快捷键说明

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