|
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
|