Blame src/vma/proto/ip_frag.cpp

Packit Service aa3af4
/*
Packit Service aa3af4
 * Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved.
Packit Service aa3af4
 *
Packit Service aa3af4
 * This software is available to you under a choice of one of two
Packit Service aa3af4
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit Service aa3af4
 * General Public License (GPL) Version 2, available from the file
Packit Service aa3af4
 * COPYING in the main directory of this source tree, or the
Packit Service aa3af4
 * BSD license below:
Packit Service aa3af4
 *
Packit Service aa3af4
 *     Redistribution and use in source and binary forms, with or
Packit Service aa3af4
 *     without modification, are permitted provided that the following
Packit Service aa3af4
 *     conditions are met:
Packit Service aa3af4
 *
Packit Service aa3af4
 *      - Redistributions of source code must retain the above
Packit Service aa3af4
 *        copyright notice, this list of conditions and the following
Packit Service aa3af4
 *        disclaimer.
Packit Service aa3af4
 *
Packit Service aa3af4
 *      - Redistributions in binary form must reproduce the above
Packit Service aa3af4
 *        copyright notice, this list of conditions and the following
Packit Service aa3af4
 *        disclaimer in the documentation and/or other materials
Packit Service aa3af4
 *        provided with the distribution.
Packit Service aa3af4
 *
Packit Service aa3af4
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service aa3af4
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service aa3af4
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service aa3af4
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service aa3af4
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service aa3af4
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service aa3af4
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service aa3af4
 * SOFTWARE.
Packit Service aa3af4
 */
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
#include "ip_frag.h"
Packit Service aa3af4
Packit Service aa3af4
#include <assert.h>
Packit Service aa3af4
#include <list>
Packit Service aa3af4
#include "utils/bullseye.h"
Packit Service aa3af4
#include "vma/event/event_handler_manager.h"
Packit Service aa3af4
#include "mem_buf_desc.h"
Packit Service aa3af4
Packit Service aa3af4
//#define IP_FRAG_DEBUG 1
Packit Service aa3af4
Packit Service aa3af4
#ifdef IP_FRAG_DEBUG
Packit Service aa3af4
#define frag_dbg(fmt, args...) \
Packit Service aa3af4
	vlog_printf(VLOG_WARNING, "%s:%d : " fmt "\n", __FUNCTION__, __LINE__,  ##args)
Packit Service aa3af4
#else
Packit Service aa3af4
#define frag_dbg(fmt, args...)
Packit Service aa3af4
#endif
Packit Service aa3af4
Packit Service aa3af4
#define frag_err(fmt, args...) \
Packit Service aa3af4
	vlog_printf(VLOG_ERROR, "%s:%d : " fmt "\n", __FUNCTION__, __LINE__,  ##args)
Packit Service aa3af4
Packit Service aa3af4
#define frag_panic(fmt, args...) \
Packit Service aa3af4
	{vlog_printf(VLOG_PANIC, "%s:%d : " fmt "\n", __FUNCTION__, __LINE__,  ##args); throw;}
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
#ifdef IP_FRAG_DEBUG
Packit Service aa3af4
static int debug_drop_every_n_pkt=0; // 0 - Disabled, 1/N is the number of packet dropped
Packit Service aa3af4
static int debug_drop_index=0;       // counter
Packit Service aa3af4
Packit Service aa3af4
static int g_ip_frag_count_check = 0;
Packit Service aa3af4
  #define MEMBUF_DEBUG_REF_INC(__p_desc__)		{g_ip_frag_count_check++; if (__p_desc__->n_ref_count!=0) frag_panic("REF_INC: p=%p\n", __p_desc__); __p_desc__->n_ref_count++;}
Packit Service aa3af4
  #define MEMBUF_DEBUG_REF_DEC(__p_desc__)      	{mem_buf_desc_t* frag_list = __p_desc__; while (frag_list) { MEMBUF_DEBUG_REF_DEC_1(frag_list); frag_list = frag_list->p_next_desc; }}
Packit Service aa3af4
  #define MEMBUF_DEBUG_REF_DEC_1(__p_desc__)		{g_ip_frag_count_check--; __p_desc__->n_ref_count--; if (__p_desc__->n_ref_count!=0) frag_panic("REF_DEC: p=%p\n", __p_desc__);}
Packit Service aa3af4
  #define PRINT_STATISTICS()				{print_statistics();}
Packit Service aa3af4
#else
Packit Service aa3af4
  #define MEMBUF_DEBUG_REF_INC(__p_desc__)
Packit Service aa3af4
  #define MEMBUF_DEBUG_REF_DEC(__p_desc__)
Packit Service aa3af4
  #define PRINT_STATISTICS()
Packit Service aa3af4
#endif
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
ip_frag_manager * g_p_ip_frag_manager = NULL;
Packit Service aa3af4
Packit Service aa3af4
ip_frag_hole_desc *hole_base = NULL;
Packit Service aa3af4
ip_frag_hole_desc *hole_free_list_head = NULL;
Packit Service aa3af4
int hole_free_list_count = 0;
Packit Service aa3af4
Packit Service aa3af4
ip_frag_desc *desc_base = NULL;
Packit Service aa3af4
ip_frag_desc *desc_free_list_head = NULL;
Packit Service aa3af4
int desc_free_list_count = 0;
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
ip_frag_manager::ip_frag_manager() : lock_spin("ip_frag_manager")
Packit Service aa3af4
{
Packit Service aa3af4
	frag_dbg("");
Packit Service aa3af4
	m_frag_counter = 0;
Packit Service aa3af4
	int i;
Packit Service aa3af4
Packit Service aa3af4
	
Packit Service aa3af4
	frag_dbg("NOTE: ip frag periodic timer is disabled until HW supports ip frag offload");
Packit Service aa3af4
	// g_p_event_handler_manager->register_timer_event(IP_FRAG_CLEANUP_INT, this, PERIODIC_TIMER, 0);
Packit Service aa3af4
Packit Service aa3af4
	frag_dbg("Created new IPFRAG MANAGER instance");
Packit Service aa3af4
	/* allocate hole list */
Packit Service aa3af4
	desc_base = new ip_frag_desc_t [IP_FRAG_MAX_DESC];
Packit Service aa3af4
	BULLSEYE_EXCLUDE_BLOCK_START
Packit Service aa3af4
	if (!desc_base) {
Packit Service aa3af4
		frag_dbg("Failed to allocate descriptor");
Packit Service aa3af4
		free_frag_resources();
Packit Service aa3af4
		throw_vma_exception("Failed to allocate descriptor");
Packit Service aa3af4
	}
Packit Service aa3af4
	hole_base = new ip_frag_hole_desc [IP_FRAG_MAX_HOLES];
Packit Service aa3af4
	if (!hole_base) {
Packit Service aa3af4
		frag_dbg("Failed to allocate hole descriptor");
Packit Service aa3af4
		free_frag_resources();
Packit Service aa3af4
		throw_vma_exception("Failed to allocate hole descriptor");
Packit Service aa3af4
	}
Packit Service aa3af4
	BULLSEYE_EXCLUDE_BLOCK_END
Packit Service aa3af4
	for (i = 0; i < IP_FRAG_MAX_DESC; i++) {
Packit Service aa3af4
		free_frag_desc(&desc_base[i]);
Packit Service aa3af4
	}
Packit Service aa3af4
	for (i = 0; i < IP_FRAG_MAX_HOLES; i++) {
Packit Service aa3af4
		free_hole_desc(&hole_base[i]);
Packit Service aa3af4
	}
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
void ip_frag_manager::free_frag_resources(void)
Packit Service aa3af4
{
Packit Service aa3af4
Packit Service aa3af4
        ip_frags_list_t::iterator i;
Packit Service aa3af4
	ip_frag_desc_t *desc;
Packit Service aa3af4
Packit Service aa3af4
	frag_dbg("NOTE: ip frag periodic timer is disabled until HW supports ip frag offload");
Packit Service aa3af4
	// g_p_event_handler_manager->unregister_timer_event(this, NULL);
Packit Service aa3af4
Packit Service aa3af4
	lock();
Packit Service aa3af4
Packit Service aa3af4
	while (m_frags.size() > 0) {
Packit Service aa3af4
		i = m_frags.begin();
Packit Service aa3af4
		desc = i->second;
Packit Service aa3af4
		destroy_frag_desc(desc);
Packit Service aa3af4
		free_frag_desc(desc);
Packit Service aa3af4
		m_frags.erase(i);
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	owner_desc_map_t temp_buff_map = m_return_descs;
Packit Service aa3af4
	m_return_descs.clear();
Packit Service aa3af4
Packit Service aa3af4
	unlock();
Packit Service aa3af4
Packit Service aa3af4
	// Must call cq_mgr outside the lock to avoid ABBA deadlock
Packit Service aa3af4
	return_buffers_to_owners(temp_buff_map);
Packit Service aa3af4
Packit Service aa3af4
	delete [] desc_base;
Packit Service aa3af4
	delete [] hole_base;
Packit Service aa3af4
	frag_dbg("Deleted IPFRAG MANAGER instance");
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
ip_frag_manager::~ip_frag_manager()
Packit Service aa3af4
{
Packit Service aa3af4
	free_frag_resources();
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
#if _BullseyeCoverage
Packit Service aa3af4
    #pragma BullseyeCoverage off
Packit Service aa3af4
#endif
Packit Service aa3af4
Packit Service aa3af4
void ip_frag_manager::print_statistics()
Packit Service aa3af4
{
Packit Service aa3af4
	frag_dbg("free desc=%d, free holes=%d, map size=%d, frags=%d", desc_free_list_count, hole_free_list_count, m_frags.size(), g_ip_frag_count_check);
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
void ip_frag_manager::free_frag(mem_buf_desc_t *frag)
Packit Service aa3af4
{
Packit Service aa3af4
	mem_buf_desc_t *tail;
Packit Service aa3af4
Packit Service aa3af4
	// There are cases that we might not have a frag list at all to release
Packit Service aa3af4
	// This is instead of checking the pointer before all calls to free_frag()
Packit Service aa3af4
	if (!frag)
Packit Service aa3af4
		return;
Packit Service aa3af4
Packit Service aa3af4
	// Change packet size - it will force packet to be discarded
Packit Service aa3af4
	frag->sz_data = IP_FRAG_FREED;
Packit Service aa3af4
Packit Service aa3af4
	// Return to owner does post_recv() which deals with linked buffers automatically
Packit Service aa3af4
	MEMBUF_DEBUG_REF_DEC(frag);
Packit Service aa3af4
Packit Service aa3af4
	tail = frag;
Packit Service aa3af4
	while (tail->p_next_desc) {
Packit Service aa3af4
		tail = tail->p_next_desc;
Packit Service aa3af4
	}
Packit Service aa3af4
	tail->p_next_desc = m_return_descs[frag->p_desc_owner];
Packit Service aa3af4
	m_return_descs[frag->p_desc_owner] = frag;
Packit Service aa3af4
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
//FIXME: use preallocated descriptors!!! instead of malloc
Packit Service aa3af4
ip_frag_hole_desc* ip_frag_manager::alloc_hole_desc()
Packit Service aa3af4
{
Packit Service aa3af4
	struct ip_frag_hole_desc *ret;
Packit Service aa3af4
	ret = hole_free_list_head;
Packit Service aa3af4
	if (!ret)
Packit Service aa3af4
		return NULL;
Packit Service aa3af4
Packit Service aa3af4
	// unlink from hole's free list
Packit Service aa3af4
	hole_free_list_head = ret->next;
Packit Service aa3af4
	hole_free_list_count--;
Packit Service aa3af4
Packit Service aa3af4
	// clear hole struct
Packit Service aa3af4
	ret->data_first = 0;
Packit Service aa3af4
	ret->data_last  = 0;
Packit Service aa3af4
	ret->next = 0;
Packit Service aa3af4
	return ret;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
void ip_frag_manager::free_hole_desc(struct ip_frag_hole_desc *p)
Packit Service aa3af4
{
Packit Service aa3af4
	// link in head of free list
Packit Service aa3af4
	p->next = hole_free_list_head;
Packit Service aa3af4
	hole_free_list_head = p;
Packit Service aa3af4
	++hole_free_list_count;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
ip_frag_desc_t *ip_frag_manager::alloc_frag_desc()
Packit Service aa3af4
{
Packit Service aa3af4
	ip_frag_desc_t *ret;
Packit Service aa3af4
	ret = desc_free_list_head;
Packit Service aa3af4
	if (!ret)
Packit Service aa3af4
		return NULL;
Packit Service aa3af4
Packit Service aa3af4
	// unlink from hole's free list
Packit Service aa3af4
	desc_free_list_head = ret->next;
Packit Service aa3af4
	--desc_free_list_count;
Packit Service aa3af4
Packit Service aa3af4
	ret->next = 0;
Packit Service aa3af4
	return ret;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
void ip_frag_manager::free_frag_desc(ip_frag_desc_t *p)
Packit Service aa3af4
{
Packit Service aa3af4
	// link in head of free list
Packit Service aa3af4
	p->next = desc_free_list_head;
Packit Service aa3af4
	desc_free_list_head = p;
Packit Service aa3af4
	desc_free_list_count++;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
void ip_frag_manager::destroy_frag_desc(ip_frag_desc_t *desc)
Packit Service aa3af4
{
Packit Service aa3af4
	struct ip_frag_hole_desc *phole, *pphole;
Packit Service aa3af4
Packit Service aa3af4
	// free holes
Packit Service aa3af4
	phole = desc->hole_list;
Packit Service aa3af4
	while (phole) {
Packit Service aa3af4
		pphole = phole;
Packit Service aa3af4
		phole = phole->next;
Packit Service aa3af4
		free_hole_desc(pphole);
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	// free frags
Packit Service aa3af4
	free_frag(desc->frag_list);
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * first fragment for given address is detected - setup
Packit Service aa3af4
 */
Packit Service aa3af4
ip_frag_desc_t *ip_frag_manager::new_frag_desc(ip_frag_key_t &key)
Packit Service aa3af4
{
Packit Service aa3af4
	ip_frag_desc_t *desc = NULL;
Packit Service aa3af4
	struct ip_frag_hole_desc *hole = NULL;
Packit Service aa3af4
Packit Service aa3af4
	hole = alloc_hole_desc();
Packit Service aa3af4
	if (!hole){
Packit Service aa3af4
		frag_dbg("NULL hole");
Packit Service aa3af4
		return NULL;
Packit Service aa3af4
	}
Packit Service aa3af4
	hole->first = IP_FRAG_NINF;
Packit Service aa3af4
	hole->last  = IP_FRAG_INF;
Packit Service aa3af4
Packit Service aa3af4
	desc = alloc_frag_desc();
Packit Service aa3af4
	if (!desc) {
Packit Service aa3af4
		frag_dbg("NULL desc");
Packit Service aa3af4
		free_hole_desc(hole);
Packit Service aa3af4
		return NULL;
Packit Service aa3af4
	}
Packit Service aa3af4
	desc->ttl = IP_FRAG_TTL;
Packit Service aa3af4
	desc->frag_list = 0;
Packit Service aa3af4
	desc->hole_list = hole;
Packit Service aa3af4
	desc->frag_counter = m_frag_counter;
Packit Service aa3af4
Packit Service aa3af4
	m_frags[key]  = desc;
Packit Service aa3af4
	return desc;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Complexity of the algorithm:
Packit Service aa3af4
 * O(1) if packets are coming in order or reverse order
Packit Service aa3af4
 * O(n^2) for random fragments, where n is number of fragments
Packit Service aa3af4
 * returns: 0 if finished OK (if the packet is complete - put it in ret)
Packit Service aa3af4
 * 		   -1 if finished not OK and this packet needs to be droped
Packit Service aa3af4
 */
Packit Service aa3af4
int ip_frag_manager::add_frag(iphdr *hdr, mem_buf_desc_t *frag, mem_buf_desc_t **ret)
Packit Service aa3af4
{
Packit Service aa3af4
	ip_frag_key_t key;
Packit Service aa3af4
	ip_frags_list_t::iterator i;
Packit Service aa3af4
	ip_frag_desc_t *desc;
Packit Service aa3af4
	struct ip_frag_hole_desc *phole, *phole_prev;
Packit Service aa3af4
	struct ip_frag_hole_desc *new_hole;
Packit Service aa3af4
	uint16_t frag_off, frag_first, frag_last;
Packit Service aa3af4
	bool more_frags;
Packit Service aa3af4
Packit Service aa3af4
	assert(hdr);
Packit Service aa3af4
	assert(frag);
Packit Service aa3af4
Packit Service aa3af4
	key.ip_id       = hdr->id;  //id is in network order!
Packit Service aa3af4
	key.src_ip      = hdr->saddr;
Packit Service aa3af4
	key.dst_ip      = hdr->daddr;
Packit Service aa3af4
	key.ipproto     = hdr->protocol;
Packit Service aa3af4
Packit Service aa3af4
	frag_dbg("Fragment: %d.%d.%d.%d->%d.%d.%d.%d id=%x size=%d",
Packit Service aa3af4
		 NIPQUAD(key.src_ip),
Packit Service aa3af4
		 NIPQUAD(key.dst_ip),
Packit Service aa3af4
		 (int)key.ip_id, (int)ntohs(hdr->tot_len));
Packit Service aa3af4
Packit Service aa3af4
#ifdef IP_FRAG_DEBUG
Packit Service aa3af4
	if (debug_drop_every_n_pkt && ((++debug_drop_index) % debug_drop_every_n_pkt == 0)) {
Packit Service aa3af4
		frag_dbg("XXX debug force dropped XXX");
Packit Service aa3af4
		return -1;
Packit Service aa3af4
	}
Packit Service aa3af4
#endif
Packit Service aa3af4
Packit Service aa3af4
	lock();
Packit Service aa3af4
Packit Service aa3af4
	MEMBUF_DEBUG_REF_INC(frag);
Packit Service aa3af4
	PRINT_STATISTICS();
Packit Service aa3af4
Packit Service aa3af4
	frag_off = ntohs(hdr->frag_off);
Packit Service aa3af4
	more_frags = frag_off & MORE_FRAGMENTS_FLAG;
Packit Service aa3af4
	frag_first = (frag_off & FRAGMENT_OFFSET) * 8;
Packit Service aa3af4
	frag_last = frag_first + ntohs(hdr->tot_len) - (hdr->ihl<<2) - 1; // frag starts from 0!!!
Packit Service aa3af4
	frag_dbg("> fragment: %d-%d, %s more frags", frag_first, frag_last, more_frags?"pending":"no");
Packit Service aa3af4
Packit Service aa3af4
	m_frag_counter++;
Packit Service aa3af4
Packit Service aa3af4
	i = m_frags.find(key);
Packit Service aa3af4
Packit Service aa3af4
	if (i == m_frags.end()) {
Packit Service aa3af4
		/* new fragment */
Packit Service aa3af4
		frag_dbg("> new fragmented packet");
Packit Service aa3af4
		desc = new_frag_desc(key);
Packit Service aa3af4
	}
Packit Service aa3af4
	else {
Packit Service aa3af4
		desc = i->second;
Packit Service aa3af4
		if ((m_frag_counter - desc->frag_counter) > IP_FRAG_SPACE) {
Packit Service aa3af4
			// discard this packet
Packit Service aa3af4
			frag_dbg("expiring packet fragments id=%x", i->first);
Packit Service aa3af4
			destroy_frag_desc(desc);
Packit Service aa3af4
			free_frag_desc(desc);
Packit Service aa3af4
			m_frags.erase(i);
Packit Service aa3af4
			i = m_frags.end();
Packit Service aa3af4
			// Add new fregment
Packit Service aa3af4
			frag_dbg("> new fragmented packet");
Packit Service aa3af4
			desc = new_frag_desc(key);
Packit Service aa3af4
		}
Packit Service aa3af4
		else {
Packit Service aa3af4
			frag_dbg("> old fragmented packet");
Packit Service aa3af4
	}
Packit Service aa3af4
	}
Packit Service aa3af4
	if (desc==NULL) {
Packit Service aa3af4
		MEMBUF_DEBUG_REF_DEC(frag);
Packit Service aa3af4
		PRINT_STATISTICS();
Packit Service aa3af4
		unlock();
Packit Service aa3af4
		return -1;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	//desc->last_frag_counter = m_frag_counter;
Packit Service aa3af4
Packit Service aa3af4
	/* 8 step reassembly algorithm as described in RFC 815 */
Packit Service aa3af4
	//step 1
Packit Service aa3af4
	phole_prev = 0; phole = desc->hole_list;
Packit Service aa3af4
	while (phole) {
Packit Service aa3af4
		//step 2 and step 3
Packit Service aa3af4
		if (frag_first >= phole->first && frag_last <= phole->last) {
Packit Service aa3af4
			break;
Packit Service aa3af4
		}
Packit Service aa3af4
		phole_prev = phole;
Packit Service aa3af4
		phole = phole->next;
Packit Service aa3af4
	}
Packit Service aa3af4
	if (!phole) {   // the right hole wasn't found
Packit Service aa3af4
		MEMBUF_DEBUG_REF_DEC(frag);
Packit Service aa3af4
		PRINT_STATISTICS();
Packit Service aa3af4
		unlock();
Packit Service aa3af4
		return -1;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	frag_dbg("> found hole: %d-%d", phole->first, phole->last);
Packit Service aa3af4
Packit Service aa3af4
	// step 4 - remove hole from list
Packit Service aa3af4
	if (phole_prev)
Packit Service aa3af4
		phole_prev->next = phole->next;
Packit Service aa3af4
	else
Packit Service aa3af4
		desc->hole_list	= phole->next;
Packit Service aa3af4
Packit Service aa3af4
	// step 5
Packit Service aa3af4
	if (frag_first > phole->first) {
Packit Service aa3af4
		new_hole                = alloc_hole_desc();
Packit Service aa3af4
		if (!new_hole) {
Packit Service aa3af4
			free_hole_desc(phole); // phole was removed from the list in step 4!
Packit Service aa3af4
			MEMBUF_DEBUG_REF_DEC(frag);
Packit Service aa3af4
			PRINT_STATISTICS();
Packit Service aa3af4
			unlock();
Packit Service aa3af4
			return -1;
Packit Service aa3af4
		}
Packit Service aa3af4
		new_hole->first         = phole->first;
Packit Service aa3af4
		new_hole->last          = frag_first-1;
Packit Service aa3af4
		new_hole->data_first    = phole->data_first;
Packit Service aa3af4
		new_hole->data_last     = frag;
Packit Service aa3af4
Packit Service aa3af4
		new_hole->next = phole->next;
Packit Service aa3af4
		if (phole_prev)
Packit Service aa3af4
			phole_prev->next = new_hole;
Packit Service aa3af4
		else
Packit Service aa3af4
			desc->hole_list	= new_hole;
Packit Service aa3af4
Packit Service aa3af4
		phole_prev = new_hole;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	//step 6
Packit Service aa3af4
	if (frag_last < phole->last && more_frags) {
Packit Service aa3af4
		new_hole                = alloc_hole_desc();
Packit Service aa3af4
		if (!new_hole) {
Packit Service aa3af4
			free_hole_desc(phole);  // phole was removed from the list in step 4!
Packit Service aa3af4
			MEMBUF_DEBUG_REF_DEC(frag);
Packit Service aa3af4
			PRINT_STATISTICS();
Packit Service aa3af4
			unlock();
Packit Service aa3af4
			return -1;
Packit Service aa3af4
		}
Packit Service aa3af4
Packit Service aa3af4
		new_hole->first         = frag_last + 1;
Packit Service aa3af4
		new_hole->last          = phole->last;
Packit Service aa3af4
		new_hole->data_first    = frag;
Packit Service aa3af4
		new_hole->data_last     = phole->data_last;
Packit Service aa3af4
Packit Service aa3af4
		new_hole->next = phole->next;
Packit Service aa3af4
		if (phole_prev)
Packit Service aa3af4
			phole_prev->next = new_hole;
Packit Service aa3af4
		else
Packit Service aa3af4
			desc->hole_list	= new_hole;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	// link frag
Packit Service aa3af4
	if (phole->data_first)
Packit Service aa3af4
		phole->data_first->p_next_desc = frag;
Packit Service aa3af4
	else
Packit Service aa3af4
		desc->frag_list	= frag;
Packit Service aa3af4
	frag->p_next_desc = phole->data_last;
Packit Service aa3af4
Packit Service aa3af4
	free_hole_desc(phole);
Packit Service aa3af4
Packit Service aa3af4
	if (!desc->hole_list) {
Packit Service aa3af4
		//step 8 - datagram assembly completed
Packit Service aa3af4
		if (i == m_frags.end())
Packit Service aa3af4
			i = m_frags.find(key);
Packit Service aa3af4
		if (i == m_frags.end()){
Packit Service aa3af4
			MEMBUF_DEBUG_REF_DEC(frag);
Packit Service aa3af4
			frag_panic("frag desc lost from map???");
Packit Service aa3af4
			//coverity unreachable
Packit Service aa3af4
			/*unlock();
Packit Service aa3af4
			return -1;*/
Packit Service aa3af4
		}
Packit Service aa3af4
		MEMBUF_DEBUG_REF_DEC(desc->frag_list);
Packit Service aa3af4
		m_frags.erase(i);
Packit Service aa3af4
		*ret = desc->frag_list;
Packit Service aa3af4
		free_frag_desc(desc);
Packit Service aa3af4
		frag_dbg("> PACKET ASSEMBLED");
Packit Service aa3af4
		PRINT_STATISTICS();
Packit Service aa3af4
		unlock();
Packit Service aa3af4
		return 0;
Packit Service aa3af4
	}
Packit Service aa3af4
	frag_dbg("> need more packets");
Packit Service aa3af4
Packit Service aa3af4
	*ret = NULL;
Packit Service aa3af4
	PRINT_STATISTICS();
Packit Service aa3af4
	unlock();
Packit Service aa3af4
	return 0;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
void ip_frag_manager::return_buffers_to_owners(const owner_desc_map_t &buff_map)
Packit Service aa3af4
{
Packit Service aa3af4
	// Assume locked !!!
Packit Service aa3af4
	owner_desc_map_t::const_iterator iter;
Packit Service aa3af4
Packit Service aa3af4
	for (iter = buff_map.begin(); iter != buff_map.end(); ++iter) {
Packit Service aa3af4
		if(g_buffer_pool_rx)
Packit Service aa3af4
			g_buffer_pool_rx->put_buffers_thread_safe(iter->second);
Packit Service aa3af4
	}
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
void ip_frag_manager::handle_timer_expired(void* user_data)
Packit Service aa3af4
{
Packit Service aa3af4
	NOT_IN_USE(user_data);
Packit Service aa3af4
	ip_frags_list_t::iterator iter, iter_temp;
Packit Service aa3af4
	ip_frag_desc_t *desc;
Packit Service aa3af4
	uint64_t delta =0;
Packit Service aa3af4
Packit Service aa3af4
	lock();
Packit Service aa3af4
	if (m_frag_counter > IP_FRAG_SPACE) {
Packit Service aa3af4
		delta = m_frag_counter - IP_FRAG_SPACE;
Packit Service aa3af4
		m_frag_counter -= delta;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	frag_dbg("calling handle_timer_expired, m_frag_counter=%ld, delta=%ld", m_frag_counter, delta);
Packit Service aa3af4
	PRINT_STATISTICS();
Packit Service aa3af4
Packit Service aa3af4
	iter = m_frags.begin();
Packit Service aa3af4
	while (iter != m_frags.end()) {
Packit Service aa3af4
		desc = iter->second;
Packit Service aa3af4
		desc->frag_counter -= delta;
Packit Service aa3af4
		if (desc->frag_counter<0 || (desc->ttl <= 0)) {	//discard this packet
Packit Service aa3af4
			frag_dbg("expiring packet fragments desc=%p (frag_counter=%d, ttl=%d)", desc, desc->frag_counter, desc->ttl);
Packit Service aa3af4
			destroy_frag_desc(desc);
Packit Service aa3af4
			free_frag_desc(desc);
Packit Service aa3af4
			iter_temp = iter++;
Packit Service aa3af4
			m_frags.erase(iter_temp);
Packit Service aa3af4
		}
Packit Service aa3af4
		else {
Packit Service aa3af4
			iter++;
Packit Service aa3af4
		}
Packit Service aa3af4
Packit Service aa3af4
		--desc->ttl;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	owner_desc_map_t temp_buff_map = m_return_descs;
Packit Service aa3af4
	m_return_descs.clear();
Packit Service aa3af4
Packit Service aa3af4
	PRINT_STATISTICS();
Packit Service aa3af4
	unlock();
Packit Service aa3af4
Packit Service aa3af4
	// Must call cq_mgr outside the lock to avoid ABBA deadlock
Packit Service aa3af4
	return_buffers_to_owners(temp_buff_map);
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
#if _BullseyeCoverage
Packit Service aa3af4
    #pragma BullseyeCoverage on
Packit Service aa3af4
#endif