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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8
9/**
10\file packet-tag-list.cc
11\brief Implements a linked list of Packet tags, including copy-on-write semantics.
12*/
13
14#include "packet-tag-list.h"
15
16#include "tag-buffer.h"
17#include "tag.h"
18
19#include "ns3/fatal-error.h"
20#include "ns3/log.h"
21
22#include <cstring>
23
24namespace ns3
25{
26
27NS_LOG_COMPONENT_DEFINE("PacketTagList");
28
29PacketTagList::TagData*
31{
32 NS_ASSERT_MSG(dataSize < std::numeric_limits<decltype(TagData::size)>::max(),
33 "Requested TagData size " << dataSize << " exceeds maximum "
34 << std::numeric_limits<decltype(TagData::size)>::max());
35
36 void* p = std::malloc(sizeof(TagData) + dataSize - 1);
37 // The matching frees are in RemoveAll and RemoveWriter
38
39 auto tag = new (p) TagData;
40 tag->size = dataSize;
41 return tag;
42}
43
44bool
46{
47 TypeId tid = tag.GetInstanceTypeId();
48 NS_LOG_FUNCTION(this << tid);
49 NS_LOG_INFO("looking for " << tid);
50
51 // trivial case when list is empty
52 if (m_next == nullptr)
53 {
54 return false;
55 }
56
57 bool found = false;
58
59 TagData** prevNext = &m_next; // previous node's next pointer
60 TagData* cur = m_next; // cursor to current node
61 TagData* it = nullptr; // utility
62
63 // Search from the head of the list until we find tid or a merge
64 while (cur != nullptr)
65 {
66 if (cur->count > 1)
67 {
68 // found merge
69 NS_LOG_INFO("found initial merge before tid");
70 break;
71 }
72 else if (cur->tid == tid)
73 {
74 NS_LOG_INFO("found tid before initial merge, calling writer");
75 found = (this->*Writer)(tag, true, cur, prevNext);
76 break;
77 }
78 else
79 {
80 // no merge or tid found yet, move on
81 prevNext = &cur->next;
82 cur = cur->next;
83 }
84 } // while !found && !cow
85
86 // did we find it or run out of tags?
87 if (cur == nullptr || found)
88 {
89 NS_LOG_INFO("returning after header with found: " << found);
90 return found;
91 }
92
93 // From here on out, we have to copy the list
94 // until we find tid, then link past it
95
96 // Before we do all that work, let's make sure tid really exists
97 for (it = cur; it != nullptr; it = it->next)
98 {
99 if (it->tid == tid)
100 {
101 break;
102 }
103 }
104 if (it == nullptr)
105 {
106 // got to end of list without finding tid
107 NS_LOG_INFO("tid not found after first merge");
108 return found;
109 }
110
111 // At this point cur is a merge, but untested for tid
112 NS_ASSERT(cur != nullptr);
113 NS_ASSERT(cur->count > 1);
114
115 /*
116 Walk the remainder of the list, copying, until we find tid
117 As we put a copy of the cur node onto our list,
118 we move the merge point down the list.
119
120 Starting position End position
121 T1 is a merge T1.count decremented
122 T2 is a merge
123 T1' is a copy of T1
124
125 other other
126 \ \
127 Prev -> T1 -> T2 -> ... T1 -> T2 -> ...
128 / / /|
129 pNext cur Prev -> T1' --/ |
130 / |
131 pNext cur
132
133 When we reach tid, we link past it, decrement count, and we're done.
134 */
135
136 // Should normally check for null cur pointer,
137 // but since we know tid exists, we'll skip this test
138 while (/* cur && */ cur->tid != tid)
139 {
140 NS_ASSERT(cur != nullptr);
141 NS_ASSERT(cur->count > 1);
142 cur->count--; // unmerge cur
143 TagData* copy = CreateTagData(cur->size);
144 copy->tid = cur->tid;
145 copy->count = 1;
146 copy->size = cur->size;
147 memcpy(copy->data, cur->data, copy->size);
148 copy->next = cur->next; // merge into tail
149 copy->next->count++; // mark new merge
150 *prevNext = copy; // point prior list at copy
151 prevNext = &copy->next; // advance
152 cur = copy->next;
153 }
154 // Sanity check:
155 NS_ASSERT(cur != nullptr); // cur should be non-zero
156 NS_ASSERT(cur->tid == tid); // cur->tid should be tid
157 NS_ASSERT(cur->count > 1); // cur should be a merge
158
159 // link around tid, removing it from our list
160 found = (this->*Writer)(tag, false, cur, prevNext);
161 return found;
162}
163
164bool
169
170// COWWriter implementing Remove
171bool
173 bool preMerge,
175 PacketTagList::TagData** prevNext)
176{
178
179 // found tid
180 bool found = true;
181 tag.Deserialize(TagBuffer(cur->data, cur->data + cur->size));
182 *prevNext = cur->next; // link around cur
183
184 if (preMerge)
185 {
186 // found tid before first merge, so delete cur
187 cur->~TagData();
188 std::free(cur);
189 }
190 else
191 {
192 // cur is always a merge at this point
193 // unmerge cur, since we linked around it already
194 cur->count--;
195 if (cur->next != nullptr)
196 {
197 // there's a next, so make it a merge
198 cur->next->count++;
199 }
200 }
201 return found;
202}
203
204bool
206{
207 bool found = COWTraverse(tag, &PacketTagList::ReplaceWriter);
208 if (!found)
209 {
210 Add(tag);
211 }
212 return found;
213}
214
215// COWWriter implementing Replace
216bool
218 bool preMerge,
220 PacketTagList::TagData** prevNext)
221{
223
224 // found tid
225 bool found = true;
226 if (preMerge)
227 {
228 // found tid before first merge, so just rewrite
229 tag.Serialize(TagBuffer(cur->data, cur->data + cur->size));
230 }
231 else
232 {
233 // cur is always a merge at this point
234 // need to copy, replace, and link past cur
235 cur->count--; // unmerge cur
237 copy->tid = tag.GetInstanceTypeId();
238 copy->count = 1;
239 tag.Serialize(TagBuffer(copy->data, copy->data + copy->size));
240 copy->next = cur->next; // merge into tail
241 if (copy->next != nullptr)
242 {
243 copy->next->count++; // mark new merge
244 }
245 *prevNext = copy; // point prior list at copy
246 }
247 return found;
248}
249
250void
251PacketTagList::Add(const Tag& tag) const
252{
253 NS_LOG_FUNCTION(this << tag.GetInstanceTypeId());
254 // ensure this id was not yet added
255 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
256 {
257 NS_ASSERT_MSG(cur->tid != tag.GetInstanceTypeId(),
258 "Error: cannot add the same kind of tag twice. The tag type is "
259 << tag.GetInstanceTypeId().GetName());
260 }
262 head->count = 1;
263 head->next = nullptr;
264 head->tid = tag.GetInstanceTypeId();
265 head->next = m_next;
266 tag.Serialize(TagBuffer(head->data, head->data + head->size));
267
268 const_cast<PacketTagList*>(this)->m_next = head;
269}
270
271bool
273{
274 NS_LOG_FUNCTION(this << tag.GetInstanceTypeId());
275 TypeId tid = tag.GetInstanceTypeId();
276 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
277 {
278 if (cur->tid == tid)
279 {
280 /* found tag */
281 tag.Deserialize(TagBuffer(cur->data, cur->data + cur->size));
282 return true;
283 }
284 }
285 /* no tag found */
286 return false;
287}
288
291{
292 return m_next;
293}
294
297{
299
300 uint32_t size = 0;
301
302 size = 4; // numberOfTags
303
304 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
305 {
306 size += 4; // TagData -> size
307
308 // TypeId hash; ensure size is multiple of 4 bytes
309 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
310 size += hashSize;
311
312 // TagData -> data; ensure size is multiple of 4 bytes
313 uint32_t tagWordSize = (cur->size + 3) & (~3);
314 size += tagWordSize;
315 }
316
317 return size;
318}
319
322{
323 NS_LOG_FUNCTION(this << buffer << maxSize);
324
325 uint32_t* p = buffer;
326 uint32_t size = 0;
327
328 size += 4;
329
330 if (size > maxSize)
331 {
332 return 0;
333 }
334
335 uint32_t* numberOfTags = p;
336 *p++ = 0;
337
338 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
339 {
340 size += 4;
341
342 if (size > maxSize)
343 {
344 return 0;
345 }
346
347 *p++ = cur->size;
348
349 NS_LOG_INFO("Serializing tag id " << cur->tid);
350
351 // ensure size is multiple of 4 bytes for 4 byte boundaries
352 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
353 size += hashSize;
354
355 if (size > maxSize)
356 {
357 return 0;
358 }
359
360 TypeId::hash_t tid = cur->tid.GetHash();
361 memcpy(p, &tid, sizeof(TypeId::hash_t));
362 p += hashSize / 4;
363
364 // ensure size is multiple of 4 bytes for 4 byte boundaries
365 uint32_t tagWordSize = (cur->size + 3) & (~3);
366 size += tagWordSize;
367
368 if (size > maxSize)
369 {
370 return 0;
371 }
372
373 memcpy(p, cur->data, cur->size);
374 p += tagWordSize / 4;
375
376 (*numberOfTags)++;
377 }
378
379 // Serialized successfully
380 return 1;
381}
382
385{
386 NS_LOG_FUNCTION(this << buffer << size);
387 const uint32_t* p = buffer;
388 uint32_t sizeCheck = size - 4;
389
390 NS_ASSERT(sizeCheck >= 4);
391 uint32_t numberOfTags = *p++;
392 sizeCheck -= 4;
393
394 NS_LOG_INFO("Deserializing number of tags " << numberOfTags);
395
396 TagData* prevTag = nullptr;
397 for (uint32_t i = 0; i < numberOfTags; ++i)
398 {
399 NS_ASSERT(sizeCheck >= 4);
400 uint32_t tagSize = *p++;
401 sizeCheck -= 4;
402
403 uint32_t hashSize = (sizeof(TypeId::hash_t) + 3) & (~3);
404 NS_ASSERT(sizeCheck >= hashSize);
405 TypeId::hash_t hash;
406 memcpy(&hash, p, sizeof(TypeId::hash_t));
407 p += hashSize / 4;
408 sizeCheck -= hashSize;
409
410 TypeId tid = TypeId::LookupByHash(hash);
411
412 NS_LOG_INFO("Deserializing tag of type " << tid);
413
414 TagData* newTag = CreateTagData(tagSize);
415 newTag->count = 1;
416 newTag->next = nullptr;
417 newTag->tid = tid;
418
419 NS_ASSERT(sizeCheck >= tagSize);
420 memcpy(newTag->data, p, tagSize);
421
422 // ensure 4 byte boundary
423 uint32_t tagWordSize = (tagSize + 3) & (~3);
424 p += tagWordSize / 4;
425 sizeCheck -= tagWordSize;
426
427 // Set link list pointers.
428 if (i == 0)
429 {
430 m_next = newTag;
431 }
432 else
433 {
434 prevTag->next = newTag;
435 }
436
437 prevTag = newTag;
438 }
439
440 NS_ASSERT(sizeCheck == 0);
441
442 // return zero if buffer did not
443 // contain a complete message
444 return (sizeCheck != 0) ? 0 : 1;
445}
446
447} /* 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:41
tag a set of bytes in a packet
Definition tag.h:28
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:48
static TypeId LookupByHash(hash_t hash)
Get a TypeId by hash.
Definition type-id.cc:904
uint32_t hash_t
Type of hash values.
Definition type-id.h:109
std::string GetName() const
Get the name.
Definition type-id.cc:1061
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#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:264
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.