A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
packet-tag-list.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006 INRIA
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18 */
19
20/**
21\file packet-tag-list.cc
22\brief Implements a linked list of Packet tags, including copy-on-write semantics.
23*/
24
25#include "packet-tag-list.h"
26
27#include "tag-buffer.h"
28#include "tag.h"
29
30#include "ns3/fatal-error.h"
31#include "ns3/log.h"
32
33#include <cstring>
34
35namespace ns3
36{
37
38NS_LOG_COMPONENT_DEFINE("PacketTagList");
39
40PacketTagList::TagData*
42{
43 NS_ASSERT_MSG(dataSize < std::numeric_limits<decltype(TagData::size)>::max(),
44 "Requested TagData size " << dataSize << " exceeds maximum "
45 << std::numeric_limits<decltype(TagData::size)>::max());
46
47 void* p = std::malloc(sizeof(TagData) + dataSize - 1);
48 // The matching frees are in RemoveAll and RemoveWriter
49
50 auto tag = new (p) TagData;
51 tag->size = dataSize;
52 return tag;
53}
54
55bool
57{
58 TypeId tid = tag.GetInstanceTypeId();
59 NS_LOG_FUNCTION(this << tid);
60 NS_LOG_INFO("looking for " << tid);
61
62 // trivial case when list is empty
63 if (m_next == nullptr)
64 {
65 return false;
66 }
67
68 bool found = false;
69
70 TagData** prevNext = &m_next; // previous node's next pointer
71 TagData* cur = m_next; // cursor to current node
72 TagData* it = nullptr; // utility
73
74 // Search from the head of the list until we find tid or a merge
75 while (cur != nullptr)
76 {
77 if (cur->count > 1)
78 {
79 // found merge
80 NS_LOG_INFO("found initial merge before tid");
81 break;
82 }
83 else if (cur->tid == tid)
84 {
85 NS_LOG_INFO("found tid before initial merge, calling writer");
86 found = (this->*Writer)(tag, true, cur, prevNext);
87 break;
88 }
89 else
90 {
91 // no merge or tid found yet, move on
92 prevNext = &cur->next;
93 cur = cur->next;
94 }
95 } // while !found && !cow
96
97 // did we find it or run out of tags?
98 if (cur == nullptr || found)
99 {
100 NS_LOG_INFO("returning after header with found: " << found);
101 return found;
102 }
103
104 // From here on out, we have to copy the list
105 // until we find tid, then link past it
106
107 // Before we do all that work, let's make sure tid really exists
108 for (it = cur; it != nullptr; it = it->next)
109 {
110 if (it->tid == tid)
111 {
112 break;
113 }
114 }
115 if (it == nullptr)
116 {
117 // got to end of list without finding tid
118 NS_LOG_INFO("tid not found after first merge");
119 return found;
120 }
121
122 // At this point cur is a merge, but untested for tid
123 NS_ASSERT(cur != nullptr);
124 NS_ASSERT(cur->count > 1);
125
126 /*
127 Walk the remainder of the list, copying, until we find tid
128 As we put a copy of the cur node onto our list,
129 we move the merge point down the list.
130
131 Starting position End position
132 T1 is a merge T1.count decremented
133 T2 is a merge
134 T1' is a copy of T1
135
136 other other
137 \ \
138 Prev -> T1 -> T2 -> ... T1 -> T2 -> ...
139 / / /|
140 pNext cur Prev -> T1' --/ |
141 / |
142 pNext cur
143
144 When we reach tid, we link past it, decrement count, and we're done.
145 */
146
147 // Should normally check for null cur pointer,
148 // but since we know tid exists, we'll skip this test
149 while (/* cur && */ cur->tid != tid)
150 {
151 NS_ASSERT(cur != nullptr);
152 NS_ASSERT(cur->count > 1);
153 cur->count--; // unmerge cur
154 TagData* copy = CreateTagData(cur->size);
155 copy->tid = cur->tid;
156 copy->count = 1;
157 copy->size = cur->size;
158 memcpy(copy->data, cur->data, copy->size);
159 copy->next = cur->next; // merge into tail
160 copy->next->count++; // mark new merge
161 *prevNext = copy; // point prior list at copy
162 prevNext = &copy->next; // advance
163 cur = copy->next;
164 }
165 // Sanity check:
166 NS_ASSERT(cur != nullptr); // cur should be non-zero
167 NS_ASSERT(cur->tid == tid); // cur->tid should be tid
168 NS_ASSERT(cur->count > 1); // cur should be a merge
169
170 // link around tid, removing it from our list
171 found = (this->*Writer)(tag, false, cur, prevNext);
172 return found;
173}
174
175bool
177{
179}
180
181// COWWriter implementing Remove
182bool
184 bool preMerge,
186 PacketTagList::TagData** prevNext)
187{
189
190 // found tid
191 bool found = true;
192 tag.Deserialize(TagBuffer(cur->data, cur->data + cur->size));
193 *prevNext = cur->next; // link around cur
194
195 if (preMerge)
196 {
197 // found tid before first merge, so delete cur
198 cur->~TagData();
199 std::free(cur);
200 }
201 else
202 {
203 // cur is always a merge at this point
204 // unmerge cur, since we linked around it already
205 cur->count--;
206 if (cur->next != nullptr)
207 {
208 // there's a next, so make it a merge
209 cur->next->count++;
210 }
211 }
212 return found;
213}
214
215bool
217{
218 bool found = COWTraverse(tag, &PacketTagList::ReplaceWriter);
219 if (!found)
220 {
221 Add(tag);
222 }
223 return found;
224}
225
226// COWWriter implementing Replace
227bool
229 bool preMerge,
231 PacketTagList::TagData** prevNext)
232{
234
235 // found tid
236 bool found = true;
237 if (preMerge)
238 {
239 // found tid before first merge, so just rewrite
240 tag.Serialize(TagBuffer(cur->data, cur->data + cur->size));
241 }
242 else
243 {
244 // cur is always a merge at this point
245 // need to copy, replace, and link past cur
246 cur->count--; // unmerge cur
248 copy->tid = tag.GetInstanceTypeId();
249 copy->count = 1;
250 tag.Serialize(TagBuffer(copy->data, copy->data + copy->size));
251 copy->next = cur->next; // merge into tail
252 if (copy->next != nullptr)
253 {
254 copy->next->count++; // mark new merge
255 }
256 *prevNext = copy; // point prior list at copy
257 }
258 return found;
259}
260
261void
262PacketTagList::Add(const Tag& tag) const
263{
264 NS_LOG_FUNCTION(this << tag.GetInstanceTypeId());
265 // ensure this id was not yet added
266 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
267 {
268 NS_ASSERT_MSG(cur->tid != tag.GetInstanceTypeId(),
269 "Error: cannot add the same kind of tag twice. The tag type is "
270 << tag.GetInstanceTypeId().GetName());
271 }
273 head->count = 1;
274 head->next = nullptr;
275 head->tid = tag.GetInstanceTypeId();
276 head->next = m_next;
277 tag.Serialize(TagBuffer(head->data, head->data + head->size));
278
279 const_cast<PacketTagList*>(this)->m_next = head;
280}
281
282bool
284{
285 NS_LOG_FUNCTION(this << tag.GetInstanceTypeId());
286 TypeId tid = tag.GetInstanceTypeId();
287 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
288 {
289 if (cur->tid == tid)
290 {
291 /* found tag */
292 tag.Deserialize(TagBuffer(cur->data, cur->data + cur->size));
293 return true;
294 }
295 }
296 /* no tag found */
297 return false;
298}
299
302{
303 return m_next;
304}
305
308{
310
311 uint32_t size = 0;
312
313 size = 4; // numberOfTags
314
315 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
316 {
317 size += 4; // TagData -> size
318
319 // TypeId hash; ensure size is multiple of 4 bytes
320 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
321 size += hashSize;
322
323 // TagData -> data; ensure size is multiple of 4 bytes
324 uint32_t tagWordSize = (cur->size + 3) & (~3);
325 size += tagWordSize;
326 }
327
328 return size;
329}
330
333{
334 NS_LOG_FUNCTION(this << buffer << maxSize);
335
336 uint32_t* p = buffer;
337 uint32_t size = 0;
338
339 size += 4;
340
341 if (size > maxSize)
342 {
343 return 0;
344 }
345
346 uint32_t* numberOfTags = p;
347 *p++ = 0;
348
349 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
350 {
351 size += 4;
352
353 if (size > maxSize)
354 {
355 return 0;
356 }
357
358 *p++ = cur->size;
359
360 NS_LOG_INFO("Serializing tag id " << cur->tid);
361
362 // ensure size is multiple of 4 bytes for 4 byte boundaries
363 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
364 size += hashSize;
365
366 if (size > maxSize)
367 {
368 return 0;
369 }
370
371 TypeId::hash_t tid = cur->tid.GetHash();
372 memcpy(p, &tid, sizeof(TypeId::hash_t));
373 p += hashSize / 4;
374
375 // ensure size is multiple of 4 bytes for 4 byte boundaries
376 uint32_t tagWordSize = (cur->size + 3) & (~3);
377 size += tagWordSize;
378
379 if (size > maxSize)
380 {
381 return 0;
382 }
383
384 memcpy(p, cur->data, cur->size);
385 p += tagWordSize / 4;
386
387 (*numberOfTags)++;
388 }
389
390 // Serialized successfully
391 return 1;
392}
393
396{
397 NS_LOG_FUNCTION(this << buffer << size);
398 const uint32_t* p = buffer;
399 uint32_t sizeCheck = size - 4;
400
401 NS_ASSERT(sizeCheck >= 4);
402 uint32_t numberOfTags = *p++;
403 sizeCheck -= 4;
404
405 NS_LOG_INFO("Deserializing number of tags " << numberOfTags);
406
407 TagData* prevTag = nullptr;
408 for (uint32_t i = 0; i < numberOfTags; ++i)
409 {
410 NS_ASSERT(sizeCheck >= 4);
411 uint32_t tagSize = *p++;
412 sizeCheck -= 4;
413
414 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
415 NS_ASSERT(sizeCheck >= hashSize);
416 TypeId::hash_t hash;
417 memcpy(&hash, p, sizeof(TypeId::hash_t));
418 p += hashSize / 4;
419 sizeCheck -= hashSize;
420
421 TypeId tid = TypeId::LookupByHash(hash);
422
423 NS_LOG_INFO("Deserializing tag of type " << tid);
424
425 TagData* newTag = CreateTagData(tagSize);
426 newTag->count = 1;
427 newTag->next = nullptr;
428 newTag->tid = tid;
429
430 NS_ASSERT(sizeCheck >= tagSize);
431 memcpy(newTag->data, p, tagSize);
432
433 // ensure 4 byte boundary
434 uint32_t tagWordSize = (tagSize + 3) & (~3);
435 p += tagWordSize / 4;
436 sizeCheck -= tagWordSize;
437
438 // Set link list pointers.
439 if (i == 0)
440 {
441 m_next = newTag;
442 }
443 else
444 {
445 prevTag->next = newTag;
446 }
447
448 prevTag = newTag;
449 }
450
451 NS_ASSERT(sizeCheck == 0);
452
453 // return zero if buffer did not
454 // contain a complete message
455 return (sizeCheck != 0) ? 0 : 1;
456}
457
458} /* namespace ns3 */
virtual TypeId GetInstanceTypeId() const =0
Get the most derived TypeId for this Object.
List of the packet tags stored in a packet.
bool Remove(Tag &tag)
Remove (the first instance of) tag from the list.
void Add(const Tag &tag) const
Add a tag to the head of this branch.
uint32_t Deserialize(const uint32_t *buffer, uint32_t size)
Deserialize tag list from the provided buffer.
uint32_t Serialize(uint32_t *buffer, uint32_t maxSize) const
Serialize the tag list into a byte buffer.
bool ReplaceWriter(Tag &tag, bool preMerge, TagData *cur, TagData **prevNext)
Copy-on-write implementing Replace.
bool Replace(Tag &tag)
Replace the value of a tag.
bool Peek(Tag &tag) const
Find a tag and return its value.
uint32_t GetSerializedSize() const
Returns number of bytes required for packet serialization.
bool COWTraverse(Tag &tag, PacketTagList::COWWriter Writer)
Traverse the list implementing copy-on-write, using Writer.
bool RemoveWriter(Tag &tag, bool preMerge, TagData *cur, TagData **prevNext)
Copy-on-write implementing Remove.
const PacketTagList::TagData * Head() const
TagData * m_next
Pointer to first TagData on the list.
static TagData * CreateTagData(size_t dataSize)
Allocate and construct a TagData struct, sizing the data area large enough to serialize dataSize byte...
bool(PacketTagList::* COWWriter)(Tag &tag, bool preMerge, TagData *cur, TagData **prevNext)
Typedef of method function pointer for copy-on-write operations.
read and write tag data
Definition: tag-buffer.h:52
tag a set of bytes in a packet
Definition: tag.h:39
virtual uint32_t GetSerializedSize() const =0
virtual void Serialize(TagBuffer i) const =0
virtual void Deserialize(TagBuffer i)=0
a unique identifier for an interface.
Definition: type-id.h:59
static TypeId LookupByHash(hash_t hash)
Get a TypeId by hash.
Definition: type-id.cc:858
uint32_t hash_t
Type of hash values.
Definition: type-id.h:120
std::string GetName() const
Get the name.
Definition: type-id.cc:992
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Defines a linked list of Packet tags, including copy-on-write semantics.
Tree node for sharing serialized tags.
TagData * next
Pointer to next in list.
TypeId tid
Type of the tag serialized into data.
uint32_t size
Size of the data buffer.
uint32_t count
Number of incoming links.
uint8_t data[1]
Serialization buffer.