* Converted the hash used to the BOpenHashTable instead of khash - basically

just applied r38391 to the IPv6 code (no time to resolve the TODO, and put
  that into a shared class).
* Fixed failure on init handling.
* Not tested, but should work at least better than before, as the hashtable has
  never been initialized before...
* This closes bug #7795.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42399 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2011-07-09 13:28:51 +00:00
parent 96b88da011
commit af66203031
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Copyright 2006-2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -77,8 +77,8 @@ typedef DoublyLinkedList<struct net_buffer,
struct ipv6_packet_key { struct ipv6_packet_key {
in6_addr source; in6_addr source;
in6_addr destination; in6_addr destination;
// We use uint32 here due to the hash function
uint32 id; uint32 id;
// using u32 for the field allows to feed the whole structure in hash func.
uint32 protocol; uint32 protocol;
}; };
@@ -95,23 +95,56 @@ public:
{ return fReceivedLastFragment { return fReceivedLastFragment
&& fBytesLeft == 0; } && fBytesLeft == 0; }
static uint32 Hash(void* _packet, const void* _key, const ipv6_packet_key& Key() const { return fKey; }
uint32 range); FragmentPacket*& HashTableLink() { return fNext; }
static int Compare(void* _packet, const void* _key);
static int32 NextOffset()
{ return offsetof(FragmentPacket, fNext); }
static void StaleTimer(struct net_timer* timer, void* data); static void StaleTimer(struct net_timer* timer, void* data);
private: private:
FragmentPacket* fNext; FragmentPacket* fNext;
struct ipv6_packet_key fKey; struct ipv6_packet_key fKey;
bool fReceivedLastFragment; uint32 fIndex;
int32 fBytesLeft; int32 fBytesLeft;
FragmentList fFragments; FragmentList fFragments;
net_timer fTimer; net_timer fTimer;
bool fReceivedLastFragment;
}; };
struct FragmentHashDefinition {
typedef ipv6_packet_key KeyType;
typedef FragmentPacket ValueType;
size_t HashKey(const KeyType& key) const
{
return jenkins_hashword((const uint32*)&key,
sizeof(ipv6_packet_key) / sizeof(uint32), 0);
}
size_t Hash(ValueType* value) const
{
return HashKey(value->Key());
}
bool Compare(const KeyType& key, ValueType* value) const
{
const ipv6_packet_key& packetKey = value->Key();
return packetKey.id == key.id
&& packetKey.source == key.source
&& packetKey.destination == key.destination
&& packetKey.protocol == key.protocol;
}
ValueType*& GetLink(ValueType* value) const
{
return value->HashTableLink();
}
};
typedef BOpenHashTable<FragmentHashDefinition, false, true> FragmentTable;
class RawSocket class RawSocket
: public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> { : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
public: public:
@@ -177,7 +210,7 @@ static net_socket_module_info* sSocketModule;
static RawSocketList sRawSockets; static RawSocketList sRawSockets;
static mutex sRawSocketsLock; static mutex sRawSocketsLock;
static mutex sFragmentLock; static mutex sFragmentLock;
static hash_table* sFragmentHash; static FragmentTable sFragmentHash;
static int32 sFragmentID; static int32 sFragmentID;
static mutex sMulticastGroupsLock; static mutex sMulticastGroupsLock;
@@ -222,7 +255,7 @@ IPv6Header::GetHeaderOffset(net_buffer* buffer, uint32 headerCode) const
return 0; return 0;
} }
// the general transport layer header case // the general transport layer header case
buffer->protocol = next; buffer->protocol = next;
return offset; return offset;
} }
@@ -241,8 +274,8 @@ RawSocket::RawSocket(net_socket* socket)
FragmentPacket::FragmentPacket(const ipv6_packet_key &key) FragmentPacket::FragmentPacket(const ipv6_packet_key &key)
: :
fKey(key), fKey(key),
fReceivedLastFragment(false), fBytesLeft(IPV6_MAXPACKET),
fBytesLeft(IPV6_MAXPACKET) fReceivedLastFragment(false)
{ {
gStackModule->init_timer(&fTimer, FragmentPacket::StaleTimer, this); gStackModule->init_timer(&fTimer, FragmentPacket::StaleTimer, this);
} }
@@ -296,6 +329,9 @@ FragmentPacket::AddFragment(uint16 start, uint16 end, net_buffer* buffer,
return B_OK; return B_OK;
} }
fIndex = buffer->index;
// adopt the buffer's device index
TRACE(" previous: %p, next: %p", previous, next); TRACE(" previous: %p, next: %p", previous, next);
// If we have parts of the data already, truncate as needed // If we have parts of the data already, truncate as needed
@@ -423,33 +459,13 @@ FragmentPacket::Reassemble(net_buffer* to)
if (buffer != to) if (buffer != to)
panic("ipv6 packet reassembly did not work correctly."); panic("ipv6 packet reassembly did not work correctly.");
to->index = fIndex;
// reset the buffer's device index
return B_OK; return B_OK;
} }
int
FragmentPacket::Compare(void* _packet, const void* _key)
{
const ipv6_packet_key* key = (ipv6_packet_key*)_key;
ipv6_packet_key* packetKey = &((FragmentPacket*)_packet)->fKey;
return memcmp(packetKey, key, sizeof(ipv6_packet_key));
}
uint32
FragmentPacket::Hash(void* _packet, const void* _key, uint32 range)
{
const struct ipv6_packet_key* key = (struct ipv6_packet_key*)_key;
FragmentPacket* packet = (FragmentPacket*)_packet;
if (packet != NULL)
key = &packet->fKey;
return jenkins_hashword((const uint32*)key,
sizeof(ipv6_packet_key) / sizeof(uint32), 0);
}
/*static*/ void /*static*/ void
FragmentPacket::StaleTimer(struct net_timer* timer, void* data) FragmentPacket::StaleTimer(struct net_timer* timer, void* data)
{ {
@@ -457,7 +473,7 @@ FragmentPacket::StaleTimer(struct net_timer* timer, void* data)
TRACE("Assembling FragmentPacket %p timed out!", packet); TRACE("Assembling FragmentPacket %p timed out!", packet);
MutexLocker locker(&sFragmentLock); MutexLocker locker(&sFragmentLock);
hash_remove(sFragmentHash, packet); sFragmentHash.Remove(packet);
locker.Unlock(); locker.Unlock();
if (!packet->fFragments.IsEmpty()) { if (!packet->fFragments.IsEmpty()) {
@@ -529,7 +545,7 @@ reassemble_fragments(const IPv6Header &header, net_buffer** _buffer, uint16 offs
// TODO: Make locking finer grained. // TODO: Make locking finer grained.
MutexLocker locker(&sFragmentLock); MutexLocker locker(&sFragmentLock);
FragmentPacket* packet = (FragmentPacket*)hash_lookup(sFragmentHash, &key); FragmentPacket* packet = sFragmentHash.Lookup(key);
if (packet == NULL) { if (packet == NULL) {
// New fragment packet // New fragment packet
packet = new (std::nothrow) FragmentPacket(key); packet = new (std::nothrow) FragmentPacket(key);
@@ -537,7 +553,7 @@ reassemble_fragments(const IPv6Header &header, net_buffer** _buffer, uint16 offs
return B_NO_MEMORY; return B_NO_MEMORY;
// add packet to hash // add packet to hash
status = hash_insert(sFragmentHash, packet); status = sFragmentHash.Insert(packet);
if (status != B_OK) { if (status != B_OK) {
delete packet; delete packet;
return status; return status;
@@ -560,7 +576,7 @@ reassemble_fragments(const IPv6Header &header, net_buffer** _buffer, uint16 offs
return status; return status;
if (packet->IsComplete()) { if (packet->IsComplete()) {
hash_remove(sFragmentHash, packet); sFragmentHash.Remove(packet);
// no matter if reassembling succeeds, we won't need this packet // no matter if reassembling succeeds, we won't need this packet
// anymore // anymore
@@ -629,7 +645,7 @@ send_fragments(ipv6_protocol* protocol, struct net_route* route,
bool lastFragment = bytesLeft == 0; bool lastFragment = bytesLeft == 0;
bufferHeader->header.ip6_nxt = IPPROTO_FRAGMENT; bufferHeader->header.ip6_nxt = IPPROTO_FRAGMENT;
bufferHeader->header.ip6_plen = bufferHeader->header.ip6_plen =
htons(fragmentLength + extensionHeadersLength); htons(fragmentLength + extensionHeadersLength);
bufferHeader.Sync(); bufferHeader.Sync();
@@ -1619,12 +1635,17 @@ init_ipv6()
sMulticastState = new MulticastState(); sMulticastState = new MulticastState();
if (sMulticastState == NULL) { if (sMulticastState == NULL) {
status = B_NO_MEMORY; status = B_NO_MEMORY;
goto err; goto err1;
} }
status = sMulticastState->Init(); status = sMulticastState->Init();
if (status != B_OK) if (status != B_OK)
goto err; goto err2;
new (&sFragmentHash) FragmentTable();
status = sFragmentHash.Init(256);
if (status != B_OK)
goto err3;
new (&sRawSockets) RawSocketList; new (&sRawSockets) RawSocketList;
// static initializers do not work in the kernel, // static initializers do not work in the kernel,
@@ -1634,18 +1655,21 @@ init_ipv6()
status = gStackModule->register_domain_protocols(AF_INET6, SOCK_RAW, 0, status = gStackModule->register_domain_protocols(AF_INET6, SOCK_RAW, 0,
NET_IPV6_MODULE_NAME, NULL); NET_IPV6_MODULE_NAME, NULL);
if (status != B_OK) if (status != B_OK)
goto err; goto err3;
status = gStackModule->register_domain(AF_INET6, "internet6", &gIPv6Module, status = gStackModule->register_domain(AF_INET6, "internet6", &gIPv6Module,
&gIPv6AddressModule, &sDomain); &gIPv6AddressModule, &sDomain);
if (status != B_OK) if (status != B_OK)
goto err; goto err3;
TRACE("init_ipv6: OK"); TRACE("init_ipv6: OK");
return B_OK; return B_OK;
err: err3:
sFragmentHash.~FragmentTable();
err2:
delete sMulticastState; delete sMulticastState;
err1:
mutex_destroy(&sReceivingProtocolLock); mutex_destroy(&sReceivingProtocolLock);
mutex_destroy(&sMulticastGroupsLock); mutex_destroy(&sMulticastGroupsLock);
mutex_destroy(&sRawSocketsLock); mutex_destroy(&sRawSocketsLock);
@@ -1665,6 +1689,7 @@ uninit_ipv6()
gStackModule->put_domain_receiving_protocol(sDomain, i); gStackModule->put_domain_receiving_protocol(sDomain, i);
} }
sFragmentHash.~FragmentTable();
delete sMulticastState; delete sMulticastState;
gStackModule->unregister_domain(sDomain); gStackModule->unregister_domain(sDomain);