network: (fixes #2221) Remove size constraint of Tag objects

This commit is contained in:
Peter D. Barnes, Jr.
2016-11-27 07:49:26 -08:00
parent 647c62936b
commit 88b9ea15bb
6 changed files with 67 additions and 58 deletions

View File

@@ -84,6 +84,9 @@ us a note on ns-developers mailing list.</p>
See <a href=https://www.nsnam.org/bugzilla/show_bug.cgi?id=2467>bug 2467</a>
for discussion.
</li>
<li><b>Packet Tag objects</b> are no longer constrained to fit within 21
bytes; a maximum size is no longer enforced.
</li>
</ul>
<hr>

View File

@@ -25,6 +25,7 @@ New user-visible features
Bugs fixed
----------
- Bug 2007 - uan: Remove deprecation on SetRxThresholdDb
- Bug 2221 - network: Remove constraint on size of ns3::Packet Tag objects
- Bug 2450 - LogDistancePropagationLossModel is not continuous
- Bug 2477 - DCF manager assert
- Bug 2492 - uan: Make use of RxGain attribute in UanPhyGen class

View File

@@ -34,6 +34,23 @@ namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("PacketTagList");
PacketTagList::TagData *
PacketTagList::CreateTagData (size_t dataSize)
{
NS_ASSERT_MSG (dataSize
< std::numeric_limits<decltype(TagData::size)>::max (),
"Requested TagData size " << dataSize
<< " exceeds maximum "
<< std::numeric_limits<decltype(TagData::size)>::max () );
void * p = std::malloc (sizeof (TagData) + dataSize - 1);
// The matching frees are in RemoveAll and RemoveWriter
TagData * tag = new (p) TagData;
tag->size = dataSize;
return tag;
}
bool
PacketTagList::COWTraverse (Tag & tag, PacketTagList::COWWriter Writer)
{
@@ -133,10 +150,11 @@ PacketTagList::COWTraverse (Tag & tag, PacketTagList::COWWriter Writer)
NS_ASSERT (cur != 0);
NS_ASSERT (cur->count > 1);
cur->count--; // unmerge cur
struct TagData * copy = new struct TagData ();
struct TagData * copy = CreateTagData (cur->size);
copy->tid = cur->tid;
copy->count = 1;
memcpy (copy->data, cur->data, TagData::MAX_SIZE);
copy->size = cur->size;
memcpy (copy->data, cur->data, copy->size);
copy->next = cur->next; // merge into tail
copy->next->count++; // mark new merge
*prevNext = copy; // point prior list at copy
@@ -170,14 +188,14 @@ PacketTagList::RemoveWriter (Tag & tag, bool preMerge,
// found tid
bool found = true;
tag.Deserialize (TagBuffer (cur->data,
cur->data + TagData::MAX_SIZE));
tag.Deserialize (TagBuffer (cur->data, cur->data + cur->size));
*prevNext = cur->next; // link around cur
if (preMerge)
{
// found tid before first merge, so delete cur
delete cur;
cur->~TagData ();
std::free (cur);
}
else
{
@@ -217,19 +235,17 @@ PacketTagList::ReplaceWriter (Tag & tag, bool preMerge,
if (preMerge)
{
// found tid before first merge, so just rewrite
tag.Serialize (TagBuffer (cur->data,
cur->data + tag.GetSerializedSize ()));
tag.Serialize (TagBuffer (cur->data, cur->data + cur->size));
}
else
{
// cur is always a merge at this point
// need to copy, replace, and link past cur
cur->count--; // unmerge cur
struct TagData * copy = new struct TagData ();
struct TagData * copy = CreateTagData (tag.GetSerializedSize ());
copy->tid = tag.GetInstanceTypeId ();
copy->count = 1;
tag.Serialize (TagBuffer (copy->data,
copy->data + tag.GetSerializedSize ()));
tag.Serialize (TagBuffer (copy->data, copy->data + copy->size));
copy->next = cur->next; // merge into tail
if (copy->next != 0)
{
@@ -247,15 +263,15 @@ PacketTagList::Add (const Tag &tag) const
// ensure this id was not yet added
for (struct TagData *cur = m_next; cur != 0; cur = cur->next)
{
NS_ASSERT_MSG (cur->tid != tag.GetInstanceTypeId (), "Error: cannot add the same kind of tag twice.");
NS_ASSERT_MSG (cur->tid != tag.GetInstanceTypeId (),
"Error: cannot add the same kind of tag twice.");
}
struct TagData * head = new struct TagData ();
struct TagData * head = CreateTagData (tag.GetSerializedSize ());
head->count = 1;
head->next = 0;
head->tid = tag.GetInstanceTypeId ();
head->next = m_next;
NS_ASSERT (tag.GetSerializedSize () <= TagData::MAX_SIZE);
tag.Serialize (TagBuffer (head->data, head->data + tag.GetSerializedSize ()));
tag.Serialize (TagBuffer (head->data, head->data + head->size));
const_cast<PacketTagList *> (this)->m_next = head;
}
@@ -270,7 +286,7 @@ PacketTagList::Peek (Tag &tag) const
if (cur->tid == tid)
{
/* found tag */
tag.Deserialize (TagBuffer (cur->data, cur->data + TagData::MAX_SIZE));
tag.Deserialize (TagBuffer (cur->data, cur->data + cur->size));
return true;
}
}

View File

@@ -119,12 +119,6 @@ class Tag;
* The portion of the list between the first branch and the target is
* shared. This portion is copied before the #Remove or #Replace is
* performed.
*
* \par <b> Memory Management: </b>
* \n
* Packet tags must serialize to a finite maximum size, see TagData
*
* This documentation entitles the original author to a free beer.
*/
class PacketTagList
{
@@ -134,37 +128,23 @@ public:
*
* See PacketTagList for a discussion of the data structure.
*
* See TagData::TagData_e for a discussion of the size limit on
* tag serialization.
* \internal
* Unfortunately this has to be public, because
* PacketTagIterator::Item::GetTag() needs the data and size values.
* The Item nested class can't be forward declared, so friending isn't
* possible.
*
* We use placement new so we can allocate enough room for the Tag
* type which will be serialized into data. See Object::Aggregates
* for a similar construction.
*/
struct TagData
{
/**
* \brief Packet Tag maximum size
*
* The maximum size (in bytes) of a Tag is stored
* in this constant.
*
* \internal
* Ideally, TagData would be 32 bytes in size, so they require
* no padding on 64-bit architectures. (The architecture
* affects the size because of the \c #next pointer.)
* This would leave 18 bytes for \c #data. However,
* ns3:Ipv6PacketInfoTag needs 19 bytes! The current
* implementation allows 20 bytes, which gives TagData
* a size of 30 bytes on 32-byte machines (which gets
* padded with 2 bytes), and 34 bytes on 64-bit machines, which
* gets padded to 40 bytes.
*/
enum TagData_e
{
MAX_SIZE = 21 /**< Size of serialization buffer #data */
};
uint8_t data[MAX_SIZE]; /**< Serialization buffer */
struct TagData * next; /**< Pointer to next in list */
TypeId tid; /**< Type of the tag serialized into #data */
uint32_t count; /**< Number of incoming links */
struct TagData * next; /**< Pointer to next in list */
uint32_t count; /**< Number of incoming links */
TypeId tid; /**< Type of the tag serialized into #data */
uint32_t size; /**< Size of the \c data buffer */
uint8_t data[1]; /**< Serialization buffer */
}; /* struct TagData */
/**
@@ -239,6 +219,16 @@ public:
const struct PacketTagList::TagData *Head (void) const;
private:
/**
* Allocate and construct a TagData struct, sizing the data area
* large enough to serialize dataSize bytes from a Tag.
*
* \param [in] dataSize The serialized size of the Tag.
* \returns The newly constructed TagData object.
*/
static
TagData * CreateTagData (size_t dataSize);
/**
* Typedef of method function pointer for copy-on-write operations
*
@@ -272,7 +262,7 @@ private:
* pointing to \pname{cur}.
* \returns True, since tag will definitely be removed.
*/
bool RemoveWriter (Tag & tag, bool preMerge,
bool RemoveWriter (Tag & tag, bool preMerge,
struct TagData * cur, struct TagData ** prevNext);
/**
* Copy-on-write implementing Replace
@@ -285,7 +275,8 @@ private:
* pointing to \pname{cur}.
* \returns True, since tag value will definitely be replaced.
*/
bool ReplaceWriter (Tag & tag, bool preMerge, struct TagData * cur, struct TagData ** prevNext);
bool ReplaceWriter (Tag & tag, bool preMerge,
struct TagData * cur, struct TagData ** prevNext);
/**
* Pointer to first \ref TagData on the list
@@ -350,13 +341,15 @@ PacketTagList::RemoveAll (void)
}
if (prev != 0)
{
delete prev;
prev->~TagData ();
std::free (prev);
}
prev = cur;
}
if (prev != 0)
{
delete prev;
prev->~TagData ();
std::free (prev);
}
m_next = 0;
}

View File

@@ -113,8 +113,7 @@ PacketTagIterator::Item::GetTag (Tag &tag) const
{
NS_ASSERT (tag.GetInstanceTypeId () == m_data->tid);
tag.Deserialize (TagBuffer ((uint8_t*)m_data->data,
(uint8_t*)m_data->data
+ PacketTagList::TagData::MAX_SIZE));
(uint8_t*)m_data->data + m_data->size));
}

View File

@@ -643,7 +643,6 @@ uint32_t
DeviceNameTag::GetSerializedSize (void) const
{
uint32_t s = 1 + m_deviceName.size(); // +1 for name length field
s = std::min (s, (uint32_t)PacketTagList::TagData::MAX_SIZE);
return s;
}
void
@@ -652,8 +651,6 @@ DeviceNameTag::Serialize (TagBuffer i) const
const char *n = m_deviceName.c_str();
uint8_t l = (uint8_t) m_deviceName.size ();
l = std::min ((uint32_t)l, (uint32_t)PacketTagList::TagData::MAX_SIZE - 1);
i.WriteU8 (l);
i.Write ( (uint8_t*) n , (uint32_t) l);
}