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

📄 ipreassembler.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
字号:
// -*- c-basic-offset: 4 -*-/* * ipreassembler.{cc,hh} -- defragments IP packets * Alexander Yip, Eddie Kohler * * Copyright (c) 2001 Massachusetts Institute of Technology * Copyright (c) 2002 International Computer Science Institute * * 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 following * conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Further elaboration of this license, including a DISCLAIMER OF ANY * WARRANTY, EXPRESS OR IMPLIED, is provided in the LICENSE file, which is * also accessible at http://www.pdos.lcs.mit.edu/click/license.html */#include <click/config.h>#include "ipreassembler.hh"#include <click/ipaddress.hh>#include <click/confparse.hh>#include <click/bitvector.hh>#include <click/error.hh>#include <click/glue.hh>#include <click/straccum.hh>CLICK_DECLS#define PACKET_CHUNK(p)		(((PacketInfo *)((p)->all_user_anno_u()))->chunk)#define PACKET_DLEN(p)		((p)->transport_length())#define IP_BYTE_OFF(iph)	((ntohs((iph)->ip_off) & IP_OFFMASK) << 3)IPReassembler::IPReassembler()    : Element(1, 1){    for (int i = 0; i < NMAP; i++)	_map[i] = 0;    static_assert(sizeof(PacketInfo) <= Packet::USER_ANNO_SIZE);    static_assert(sizeof(ChunkLink) <= 8);}IPReassembler::~IPReassembler(){}voidIPReassembler::notify_noutputs(int n){    set_noutputs(n < 2 ? 1 : 2);}intIPReassembler::configure(Vector<String> &conf, ErrorHandler *errh){    _mem_high_thresh = 256 * 1024;    if (cp_va_parse(conf, this, errh,		    cpKeywords,		    "HIMEM", cpUnsigned, "memory consumption limit", &_mem_high_thresh,		    cpEnd) < 0)	return -1;    _mem_low_thresh = (_mem_high_thresh >> 2) * 3;    return 0;}intIPReassembler::initialize(ErrorHandler *){    _mem_used = 0;    _reap_time = 0;    return 0;}voidIPReassembler::cleanup(CleanupStage){    for (int i = 0; i < NMAP; i++)	while (_map[i]) {	    WritablePacket *next = (WritablePacket *)(_map[i]->next());	    _map[i]->kill();	    _map[i] = next;	}}voidIPReassembler::check_error(ErrorHandler *errh, int bucket, const Packet *p, const char *format, ...){    const click_ip *iph = p->ip_header();    va_list val;    va_start(val, format);    StringAccum sa;    sa << "buck " << bucket << ": ";    if (iph)	sa << iph->ip_src << " > " << iph->ip_dst << " [" << ntohs(iph->ip_id) << ':' << PACKET_DLEN(p) << ((iph->ip_off & htons(IP_MF)) ? "+]: " : "]: ");    sa << format;    errh->verror(ErrorHandler::ERR_ERROR, String(), sa.cc(), val);    va_end(val);}intIPReassembler::check(ErrorHandler *errh){    if (!errh)	errh = ErrorHandler::default_handler();    uint32_t mem_used = 0;    for (int b = 0; b < NMAP; b++)	for (WritablePacket *q = _map[b]; q; q = (WritablePacket *)(q->next()))	    if (const click_ip *qip = q->ip_header()) {		if (bucketno(qip) != b)		    check_error(errh, b, q, "in wrong bucket");		mem_used += IPH_MEM_USED + q->transport_length();		ChunkLink *chunk = &PACKET_CHUNK(q);		int off = 0;#if VERBOSE_DEBUG		check_error(errh, b, q, "");		StringAccum sa;		while (chunk && (!off || off < q->transport_length())) {		    sa << " (" << chunk->off << ',' << chunk->lastoff << ')';		    off = chunk->lastoff;		    chunk = next_chunk(q, chunk);		}		errh->message("  %s", sa.cc());		chunk = &PACKET_CHUNK(q);		off = 0;#endif		while (chunk) {		    if (chunk->off >= chunk->lastoff			|| chunk->lastoff > q->transport_length()			|| (off != 0 && chunk->off < off + 8)) {			check_error(errh, b, q, "bad chunk (%d, %d) at %d", chunk->off, chunk->lastoff, off);			break;		    }		    off = chunk->lastoff;		    chunk = next_chunk(q, chunk);		}	    } else		errh->error("buck %d: missing IP header", b);    if (mem_used != _mem_used)	errh->error("bad mem_used: have %u, claim %u", mem_used, _mem_used);    return 0;}WritablePacket *IPReassembler::find_queue(Packet *p, WritablePacket ***store_pprev){    const click_ip *iph = p->ip_header();    int bucket = bucketno(iph);    WritablePacket **pprev = &_map[bucket];    WritablePacket *q;    for (q = *pprev; q; pprev = (WritablePacket **)&q->next(), q = *pprev) {	const click_ip *qiph = q->ip_header();	if (same_segment(iph, qiph)) {	    *store_pprev = pprev;	    return q;	}    }    *store_pprev = &_map[bucket];    return 0;}Packet *IPReassembler::emit_whole_packet(WritablePacket *q, WritablePacket **q_pprev,				 Packet *p_in){    *q_pprev = (WritablePacket *)q->next();    click_ip *q_iph = q->ip_header();    q_iph->ip_len = htons(q->network_length());    q_iph->ip_sum = 0;    q_iph->ip_sum = click_in_cksum((const unsigned char *)q_iph, q_iph->ip_hl << 2);    // zero out the annotations we used    memset(&PACKET_CHUNK(q), 0, sizeof(struct PacketInfo) - offsetof(struct PacketInfo, chunk));    q->set_timestamp_anno(p_in->timestamp_anno());    q->set_next(0);    p_in->kill();    _mem_used -= IPH_MEM_USED + q->transport_length();    return q;}voidIPReassembler::make_queue(Packet *p, WritablePacket **q_pprev){    const click_ip *iph = p->ip_header();    int p_off = IP_BYTE_OFF(iph);    int p_lastoff = p_off + PACKET_DLEN(p);    int hl = (p_off == 0 ? iph->ip_hl << 2 : 20);    WritablePacket *q = Packet::make(60 - hl, 0, hl + p_lastoff, 0);    if (!q) {	click_chatter("out of memory");	return;    }    _mem_used += IPH_MEM_USED + p_lastoff;    // copy IP header and annotations if appropriate    q->set_ip_header((click_ip *)q->data(), hl);    memcpy(q->ip_header(), iph, hl);    click_ip *q_iph = q->ip_header();    q_iph->ip_off = (iph->ip_off & ~htons(IP_OFFMASK)); // leave MF, DF, RF    if (p_off == 0)	q->copy_annotations(p);        // copy data    memcpy(q->transport_header() + p_off, p->transport_header(), PACKET_DLEN(p));    PACKET_CHUNK(q).off = p_off;    PACKET_CHUNK(q).lastoff = p_lastoff;    // link it up    q->set_next(*q_pprev);    *q_pprev = q;        check();}IPReassembler::ChunkLink *IPReassembler::next_chunk(WritablePacket *q, ChunkLink *chunk){    if (chunk->lastoff >= q->transport_length())	return 0;    else	return (ChunkLink *)(q->transport_header() + chunk->lastoff);}Packet *IPReassembler::simple_action(Packet *p){    // check common case: not a fragment     const click_ip *iph = p->ip_header();    assert(iph);    if (!IP_ISFRAG(iph))	return p;    // reap if necessary    int now = p->timestamp_anno().sec();    if (!now) {	p->timestamp_anno().set_now();	now = p->timestamp_anno().sec();    }    if (now >= _reap_time)	reap(now);    // calculate packet edges    int p_off = IP_BYTE_OFF(iph);    int p_lastoff = p_off + ntohs(iph->ip_len) - (iph->ip_hl << 2);    // check uncommon, but annoying, case: bad length, bad length + offset,    // or middle fragment length not a multiple of 8 bytes    if (p_lastoff > 0xFFFF || p_lastoff <= p_off	|| ((p_lastoff & 7) != 0 && (iph->ip_off & htons(IP_MF)) != 0)	|| PACKET_DLEN(p) < p_lastoff - p_off) {	p->kill();	return 0;    }    p->take(PACKET_DLEN(p) - (p_lastoff - p_off));    // otherwise, we need to keep the packet    // clean up memory if necessary    if (_mem_used > _mem_high_thresh)	reap_overfull(now);    // get its Packet queue    WritablePacket **q_pprev;    WritablePacket *q = find_queue(p, &q_pprev);    if (!q) {			// make a new queue	make_queue(p, q_pprev);	p->kill();	return 0;    }    WritablePacket *q_bucket_next = (WritablePacket *)(q->next());    // extend the packet if necessary    if (p_lastoff > q->transport_length()) {	// error if packet already completed	if (!(q->ip_header()->ip_off & htons(IP_MF))) {	    p->kill();	    return 0;	}	// Figure out how much space to request. Add 8 extra bytes to ensure	// room for a ChunkLink, and request extra space if this packet has MF	// set. XXX This algorithm could result in a number of intermediate	// packet copies linear in the final packet length.	int old_transport_length = q->transport_length();	assert((old_transport_length & 7) == 0);	int want_space = p_lastoff - old_transport_length + 8;	if (iph->ip_off & htons(IP_MF))	    want_space += (p_lastoff - p_off);	// request space	if (!(q = q->put(want_space))) {	    click_chatter("out of memory");	    *q_pprev = q_bucket_next;	    _mem_used -= IPH_MEM_USED + old_transport_length;	    p->kill();	    return 0;	}	// get rid of extra space	q->take(q->transport_length() - p_lastoff);	// hook up packet, and add final chunk	*q_pprev = q;	ChunkLink *last_chunk = (ChunkLink *)(q->transport_header() + old_transport_length);	last_chunk->off = last_chunk->lastoff = p_lastoff;	_mem_used += p_lastoff - old_transport_length;    }    // find chunks before and after p    ChunkLink *chunk = &PACKET_CHUNK(q);    while (chunk->lastoff < p_off)	chunk = next_chunk(q, chunk);    ChunkLink *last = chunk;    while (last && last->lastoff < p_lastoff)	last = next_chunk(q, last);    // patch chunks    assert(chunk && last);    if (p_lastoff < last->off) {	ChunkLink *new_chunk = (ChunkLink *)(q->transport_header() + p_lastoff);	*new_chunk = *last;	chunk->lastoff = p_lastoff;    } else	chunk->lastoff = last->lastoff;    if (p_off < chunk->off)	chunk->off = p_off;    // copy p's data into q    memcpy(q->transport_header() + p_off, p->transport_header(), p_lastoff - p_off);    // copy p's annotations and IP header if it is the first packet    if (p_off == 0) {	int old_ip_off = q->ip_header()->ip_off;	int hl = iph->ip_hl << 2;	if (hl > (int) q->network_header_length())	    (void) q->nonunique_push(hl - q->network_header_length());	else	    q->pull(q->network_header_length() - hl);	q->set_ip_header((click_ip *)(q->transport_header() - hl), hl);	memcpy(q->ip_header(), p->ip_header(), hl);	q->ip_header()->ip_off = old_ip_off;	//q->copy_annotations(p); XXX    }    // clear MF if incoming packet has it cleared    if (!(iph->ip_off & htons(IP_MF)))	q->ip_header()->ip_off &= ~htons(IP_MF);        // Are we done with this packet?    if ((q->ip_header()->ip_off & htons(IP_MF)) == 0	&& PACKET_CHUNK(q).off == 0	&& PACKET_CHUNK(q).lastoff == q->transport_length())	return emit_whole_packet(q, q_pprev, p);    // Otherwise, done for now    //check();    p->kill();    return 0;}voidIPReassembler::reap_overfull(int now){    check();    // First throw away fragments at least 10 seconds old, then at least 5    // seconds old, then any fragments.    for (int delta = 10; delta >= 0; delta -= 5)	for (int bucket = 0; bucket < NMAP; bucket++) {	    WritablePacket **pprev = &_map[bucket];	    for (WritablePacket *q = *pprev; q; q = *pprev)		if (q->timestamp_anno().sec() < now - delta) {		    *pprev = (WritablePacket *)q->next();		    _mem_used -= IPH_MEM_USED + q->transport_length();		    q->set_next(0);		    checked_output_push(1, q);		    if (_mem_used <= _mem_low_thresh)			return;		} else		    pprev = (WritablePacket **)&q->next();	}    click_chatter("IPReassembler: cannot free enough memory!");}voidIPReassembler::reap(int now){    // look at all queues. If no activity for 30 seconds, kill that queue    int kill_time = now - REAP_TIMEOUT;    for (int i = 0; i < NMAP; i++) {	WritablePacket **q_pprev = &_map[i];	for (WritablePacket *q = *q_pprev; q; ) {	    if (q->timestamp_anno().sec() < kill_time) {		*q_pprev = (WritablePacket *)q->next();		q->set_next(0);		checked_output_push(1, q);	    } else		q_pprev = (WritablePacket **)&q->next();	    q = *q_pprev;	}    }    _reap_time = now + REAP_INTERVAL;}CLICK_ENDDECLSEXPORT_ELEMENT(IPReassembler)

⌨️ 快捷键说明

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