/** * first fragment for given address is detected - setup */ ip_frag_desc_t *ip_frag_manager::new_frag_desc(ip_frag_key_t &key) { ip_frag_desc_t *desc = NULL; struct ip_frag_hole_desc *hole = NULL; hole = alloc_hole_desc(); if (!hole){ frag_dbg("NULL hole"); return NULL; } hole->first = IP_FRAG_NINF; hole->last = IP_FRAG_INF; desc = alloc_frag_desc(); if (!desc) { frag_dbg("NULL desc"); free_hole_desc(hole); return NULL; } desc->ttl = IP_FRAG_TTL; desc->frag_list = 0; desc->hole_list = hole; desc->frag_counter = m_frag_counter; m_frags[key] = desc; return desc; }
ip_frag_manager::ip_frag_manager() : lock_spin("ip_frag_manager") { frag_dbg(""); m_frag_counter = 0; int i; frag_dbg("NOTE: ip frag periodic timer is disabled until HW supports ip frag offload"); // g_p_event_handler_manager->register_timer_event(IP_FRAG_CLEANUP_INT, this, PERIODIC_TIMER, 0); frag_dbg("Created new IPFRAG MANAGER instance"); /* allocate hole list */ desc_base = new ip_frag_desc_t [IP_FRAG_MAX_DESC]; BULLSEYE_EXCLUDE_BLOCK_START if (!desc_base) { frag_dbg("Failed to allocate descriptor"); free_frag_resources(); throw_vma_exception("Failed to allocate descriptor"); } hole_base = new ip_frag_hole_desc [IP_FRAG_MAX_HOLES]; if (!hole_base) { frag_dbg("Failed to allocate hole descriptor"); free_frag_resources(); throw_vma_exception("Failed to allocate hole descriptor"); } BULLSEYE_EXCLUDE_BLOCK_END for (i = 0; i < IP_FRAG_MAX_DESC; i++) { free_frag_desc(&desc_base[i]); } for (i = 0; i < IP_FRAG_MAX_HOLES; i++) { free_hole_desc(&hole_base[i]); } }
void ip_frag_manager::free_frag_resources(void) { ip_frags_list_t::iterator i; ip_frag_desc_t *desc; frag_dbg("NOTE: ip frag periodic timer is disabled until HW supports ip frag offload"); // g_p_event_handler_manager->unregister_timer_event(this, NULL); lock(); while (m_frags.size() > 0) { i = m_frags.begin(); desc = i->second; destroy_frag_desc(desc); free_frag_desc(desc); m_frags.erase(i); } owner_desc_map_t temp_buff_map = m_return_descs; m_return_descs.clear(); unlock(); // Must call cq_mgr outside the lock to avoid ABBA deadlock return_buffers_to_owners(temp_buff_map); delete [] desc_base; delete [] hole_base; frag_dbg("Deleted IPFRAG MANAGER instance"); }
static void pico_ipv6_frag_timer_on(void) { ipv6_fragments_timer = pico_timer_add(PICO_IPV6_FRAG_TIMEOUT, pico_frag_expire, &ipv6_fragments); if (!ipv6_fragments_timer) { frag_dbg("FRAG: Failed to start IPv6 expiration timer\n"); pico_fragments_empty_tree(&ipv6_fragments); } }
void ip_frag_manager::handle_timer_expired(void* user_data) { NOT_IN_USE(user_data); ip_frags_list_t::iterator iter, iter_temp; ip_frag_desc_t *desc; uint64_t delta =0; lock(); if (m_frag_counter > IP_FRAG_SPACE) { delta = m_frag_counter - IP_FRAG_SPACE; m_frag_counter -= delta; } frag_dbg("calling handle_timer_expired, m_frag_counter=%ld, delta=%ld", m_frag_counter, delta); PRINT_STATISTICS(); iter = m_frags.begin(); while (iter != m_frags.end()) { desc = iter->second; desc->frag_counter -= delta; if (desc->frag_counter<0 || (desc->ttl <= 0)) { //discard this packet frag_dbg("expiring packet fragments desc=%p (frag_counter=%d, ttl=%d)", desc, desc->frag_counter, desc->ttl); destroy_frag_desc(desc); free_frag_desc(desc); iter_temp = iter++; m_frags.erase(iter_temp); } else { iter++; } --desc->ttl; } owner_desc_map_t temp_buff_map = m_return_descs; m_return_descs.clear(); PRINT_STATISTICS(); unlock(); // Must call cq_mgr outside the lock to avoid ABBA deadlock return_buffers_to_owners(temp_buff_map); }
/** * Complexity of the algorithm: * O(1) if packets are coming in order or reverse order * O(n^2) for random fragments, where n is number of fragments * returns: 0 if finished OK (if the packet is complete - put it in ret) * -1 if finished not OK and this packet needs to be droped */ int ip_frag_manager::add_frag(iphdr *hdr, mem_buf_desc_t *frag, mem_buf_desc_t **ret) { ip_frag_key_t key; ip_frags_list_t::iterator i; ip_frag_desc_t *desc; struct ip_frag_hole_desc *phole, *phole_prev; struct ip_frag_hole_desc *new_hole; uint16_t frag_off, frag_first, frag_last; bool more_frags; assert(hdr); assert(frag); key.ip_id = hdr->id; //id is in network order! key.src_ip = hdr->saddr; key.dst_ip = hdr->daddr; key.ipproto = hdr->protocol; frag_dbg("Fragment: %d.%d.%d.%d->%d.%d.%d.%d id=%x size=%d", NIPQUAD(key.src_ip), NIPQUAD(key.dst_ip), (int)key.ip_id, (int)ntohs(hdr->tot_len)); #ifdef IP_FRAG_DEBUG if (debug_drop_every_n_pkt && ((++debug_drop_index) % debug_drop_every_n_pkt == 0)) { frag_dbg("XXX debug force dropped XXX"); return -1; } #endif lock(); MEMBUF_DEBUG_REF_INC(frag); PRINT_STATISTICS(); frag_off = ntohs(hdr->frag_off); more_frags = frag_off & MORE_FRAGMENTS_FLAG; frag_first = (frag_off & FRAGMENT_OFFSET) * 8; frag_last = frag_first + ntohs(hdr->tot_len) - (hdr->ihl<<2) - 1; // frag starts from 0!!! frag_dbg("> fragment: %d-%d, %s more frags", frag_first, frag_last, more_frags?"pending":"no"); m_frag_counter++; i = m_frags.find(key); if (i == m_frags.end()) { /* new fragment */ frag_dbg("> new fragmented packet"); desc = new_frag_desc(key); } else { desc = i->second; if ((m_frag_counter - desc->frag_counter) > IP_FRAG_SPACE) { // discard this packet frag_dbg("expiring packet fragments id=%x", i->first); destroy_frag_desc(desc); free_frag_desc(desc); m_frags.erase(i); i = m_frags.end(); // Add new fregment frag_dbg("> new fragmented packet"); desc = new_frag_desc(key); } else { frag_dbg("> old fragmented packet"); } } if (desc==NULL) { MEMBUF_DEBUG_REF_DEC(frag); PRINT_STATISTICS(); unlock(); return -1; } //desc->last_frag_counter = m_frag_counter; /* 8 step reassembly algorithm as described in RFC 815 */ //step 1 phole_prev = 0; phole = desc->hole_list; while (phole) { //step 2 and step 3 if (frag_first >= phole->first && frag_last <= phole->last) { break; } phole_prev = phole; phole = phole->next; } if (!phole) { // the right hole wasn't found MEMBUF_DEBUG_REF_DEC(frag); PRINT_STATISTICS(); unlock(); return -1; } frag_dbg("> found hole: %d-%d", phole->first, phole->last); // step 4 - remove hole from list if (phole_prev) phole_prev->next = phole->next; else desc->hole_list = phole->next; // step 5 if (frag_first > phole->first) { new_hole = alloc_hole_desc(); if (!new_hole) { free_hole_desc(phole); // phole was removed from the list in step 4! MEMBUF_DEBUG_REF_DEC(frag); PRINT_STATISTICS(); unlock(); return -1; } new_hole->first = phole->first; new_hole->last = frag_first-1; new_hole->data_first = phole->data_first; new_hole->data_last = frag; new_hole->next = phole->next; if (phole_prev) phole_prev->next = new_hole; else desc->hole_list = new_hole; phole_prev = new_hole; } //step 6 if (frag_last < phole->last && more_frags) { new_hole = alloc_hole_desc(); if (!new_hole) { free_hole_desc(phole); // phole was removed from the list in step 4! MEMBUF_DEBUG_REF_DEC(frag); PRINT_STATISTICS(); unlock(); return -1; } new_hole->first = frag_last + 1; new_hole->last = phole->last; new_hole->data_first = frag; new_hole->data_last = phole->data_last; new_hole->next = phole->next; if (phole_prev) phole_prev->next = new_hole; else desc->hole_list = new_hole; } // link frag if (phole->data_first) phole->data_first->p_next_desc = frag; else desc->frag_list = frag; frag->p_next_desc = phole->data_last; free_hole_desc(phole); if (!desc->hole_list) { //step 8 - datagram assembly completed if (i == m_frags.end()) i = m_frags.find(key); if (i == m_frags.end()){ MEMBUF_DEBUG_REF_DEC(frag); frag_panic("frag desc lost from map???"); //coverity unreachable /*unlock(); return -1;*/ } MEMBUF_DEBUG_REF_DEC(desc->frag_list); m_frags.erase(i); *ret = desc->frag_list; free_frag_desc(desc); frag_dbg("> PACKET ASSEMBLED"); PRINT_STATISTICS(); unlock(); return 0; } frag_dbg("> need more packets"); *ret = NULL; PRINT_STATISTICS(); unlock(); return 0; }
void ip_frag_manager::print_statistics() { 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); }