/* * Copyright (c) 2015 Meisaka Yukara. * Copyright (c) 2016, 2017 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * net/packet.cpp * Reference counted network packets. */ #include #include #include #include #include #include #include namespace Sortix { // Limit the memory usage of network packets to this fraction of total memory. // This constant is documented in if(4) under NOTES. static const size_t MAX_PACKET_FRACTION = 16; // Keep this amount of virtually mapped buffers around at all times. // This constant is documented in if(4) under NOTES. static const size_t PACKET_CACHE_TARGET_SIZE = 384; // A cache of physical memory allocations for quick allocation to new packets. static kthread_mutex_t packet_cache_lock = KTHREAD_MUTEX_INITIALIZER; static paddrmapped_t* packet_cache = NULL; static size_t packet_cache_used = 0; static size_t packet_cache_allocated = 0; static size_t packet_count = 0; Packet::Packet(paddrmapped_t _pmap) : pmap(_pmap) { from = (unsigned char*) pmap.from; length = 0; offset = 0; netif = NULL; packet_count++; } Packet::~Packet() { // Refuse to do recursive destructor calls that could stack overflow. assert(!next); ScopedLock lock(&packet_cache_lock); if ( packet_cache_used < packet_cache_allocated ) packet_cache[packet_cache_used++] = pmap; else FreeAllocatedAndMappedPage(&pmap); packet_count--; } Ref GetPacket() { ScopedLock lock(&packet_cache_lock); if ( packet_cache == NULL ) { size_t new_allocated = PACKET_CACHE_TARGET_SIZE; packet_cache = new paddrmapped_t[new_allocated]; if ( !packet_cache ) return errno = ENOBUFS, Ref(NULL); packet_cache_allocated = new_allocated; } paddrmapped_t pmap; // Fast reuse of an existing physical allocation if available. if ( 0 < packet_cache_used ) pmap = packet_cache[--packet_cache_used]; // Otherwise make a new physical allocation for the packet. else { size_t total_memory; Memory::Statistics(NULL, &total_memory); size_t total_pages = total_memory / Page::Size(); size_t max_packets = total_pages / MAX_PACKET_FRACTION; if ( max_packets <= packet_count ) return errno = ENOBUFS, Ref(NULL); if ( !AllocateAndMapPage(&pmap, PAGE_USAGE_NETWORK_PACKET) ) return errno = ENOBUFS, Ref(NULL); } Ref pkt = Ref(new Packet(pmap)); if ( !pkt ) { FreeAllocatedAndMappedPage(&pmap); return errno = ENOBUFS, Ref(NULL); } return pkt; } } // namespace Sortix