A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
packet-tag-list.h
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#ifndef PACKET_TAG_LIST_H
9#define PACKET_TAG_LIST_H
10
11/**
12\file packet-tag-list.h
13\brief Defines a linked list of Packet tags, including copy-on-write semantics.
14*/
15
16#include "ns3/type-id.h"
17
18#include <ostream>
19#include <stdint.h>
20
21namespace ns3
22{
23
24class Tag;
25
26/**
27 * @ingroup packet
28 *
29 * @brief List of the packet tags stored in a packet.
30 *
31 * This class is mostly private to the Packet implementation and users
32 * should never have to access it directly.
33 *
34 * @internal
35 *
36 * The implementation of this class is a bit tricky. Refer to this
37 * diagram in the discussion that follows.
38 *
39 * @dot
40 * digraph {
41 * rankdir = "LR";
42 * clusterrank = local;
43 * node [ shape = record, fontname="FreeSans", fontsize="10" ];
44 * oth [ label="<l> Other branch | <n> next | <c> ..." ];
45 * PTL1 [ label="<l> PacketTagList A | <n> m_next" , shape=Mrecord];
46 * PTL2 [ label="<l> PacketTagList B | <n> m_next" , shape=Mrecord];
47 * oth:n -> T7:l ;
48 * PTL2:n -> T6:l ;
49 * PTL1:n -> T5:l ;
50 * T1 [ label="<l> T1 | <n> next | <c> count = 1" ];
51 * T2 [ label="<l> T2 | <n> next | <c> count = 1" ];
52 * T3 [ label="<l> T3 | <n> next | <c> count = 2" ];
53 * T4 [ label="<l> T4 | <n> next | <c> count = 1" ];
54 * T5 [ label="<l> T5 | <n> next | <c> count = 2" ];
55 * T6 [ label="<l> T6 | <n> next | <c> count = 1" ];
56 * T7 [ label="<l> T7 | <n> next | <c> count = 1" ];
57 * NULL [ label="0", shape = ellipse ];
58 * subgraph cluster_list {
59 * penwidth = 0;
60 * T6:n -> T5:l ;
61 * T5:n -> T4:l ;
62 * T4:n -> T3:l ;
63 * T7:n -> T3:l ;
64 * T3:n -> T2:l ;
65 * T2:n -> T1:l ;
66 * T1:n -> NULL ;
67 * };
68 * }
69 * @enddot
70 *
71 * - Tags are stored in serialized form in a tree of TagData
72 * structures. (<tt>T1-T7</tt> in the diagram)
73 *
74 * - Each TagData points (\c next pointers in the diagram)
75 * toward the root of the tree, which is a null pointer.
76 *
77 * - \c count is the number of incoming pointers to this
78 * TagData. Branch points, where branches merge or join, have
79 * <tt>count > 1</tt> (\c T3, \c T5); successive links along
80 * a branch have <tt>count = 1</tt> (\c T1, \c T2, \c T4, \c T6, \c T7).
81 *
82 * - Each PacketTagList points to a specific TagData,
83 * which is the most recent Tag added to the packet. (<tt>T5-T7</tt>)
84 *
85 * - Conceptually, therefore, each Packet has a PacketTagList which
86 * points to a singly-linked list of TagData.
87 *
88 * @par <b> Copy-on-write </b> is implemented as follows:
89 *
90 * - #Add prepends the new tag to the list (growing that branch of the tree,
91 * as \c T6). This is a constant time operation, and does not affect
92 * any other #PacketTagList's, hence this is a \c const function.
93 *
94 * - Copy constructor (PacketTagList(const PacketTagList & o))
95 * and assignment (#operator=(const PacketTagList & o))
96 * simply join the tree at the same place as the original
97 * PacketTagList \c o, incrementing the \c count.
98 * For assignment, the old branch is deleted, up to
99 * the first branch point, which has its \c count decremented.
100 * (PacketTagList \c B started as a copy of PacketTagList \c A,
101 * before \c T6 was added to \c B).
102 *
103 * - #Remove and #Replace are a little tricky, depending on where the
104 * target tag is found relative to the first branch point:
105 * - \e Target before <em> the first branch point: </em> \n
106 * The target is just dealt with in place (linked around and deleted,
107 * in the case of #Remove; rewritten in the case of #Replace).
108 * - \e Target at or after <em> the first branch point: </em> \n
109 * The portion of the list between the first branch and the target is
110 * shared. This portion is copied before the #Remove or #Replace is
111 * performed.
112 */
114{
115 public:
116 /**
117 * Tree node for sharing serialized tags.
118 *
119 * See PacketTagList for a discussion of the data structure.
120 *
121 * @internal
122 * Unfortunately this has to be public, because
123 * PacketTagIterator::Item::GetTag() needs the data and size values.
124 * The Item nested class can't be forward declared, so friending isn't
125 * possible.
126 *
127 * We use placement new so we can allocate enough room for the Tag
128 * type which will be serialized into data. See Object::Aggregates
129 * for a similar construction.
130 */
131 struct TagData
132 {
133 TagData* next; //!< Pointer to next in list
134 uint32_t count; //!< Number of incoming links
135 TypeId tid; //!< Type of the tag serialized into #data
136 uint32_t size; //!< Size of the \c data buffer
137 uint8_t data[1]; //!< Serialization buffer
138 };
139
140 /**
141 * Create a new PacketTagList.
142 */
143 inline PacketTagList();
144 /**
145 * Copy constructor
146 *
147 * @param [in] o The PacketTagList to copy.
148 *
149 * This makes a light-weight copy by #RemoveAll, then
150 * pointing to the same \ref TagData as \pname{o}.
151 */
152 inline PacketTagList(const PacketTagList& o);
153 /**
154 * Assignment
155 *
156 * @param [in] o The PacketTagList to copy.
157 * @returns the copied object
158 *
159 * This makes a light-weight copy by #RemoveAll, then
160 * pointing to the same \ref TagData as \pname{o}.
161 */
162 inline PacketTagList& operator=(const PacketTagList& o);
163 /**
164 * Destructor
165 *
166 * #RemoveAll's the tags up to the first merge.
167 */
168 inline ~PacketTagList();
169
170 /**
171 * Add a tag to the head of this branch.
172 *
173 * @param [in] tag The tag to add
174 */
175 void Add(const Tag& tag) const;
176 /**
177 * Remove (the first instance of) tag from the list.
178 *
179 * @param [in,out] tag The tag type to remove. If found,
180 * \pname{tag} is set to the value of the tag found.
181 * @returns True if \pname{tag} is found, false otherwise.
182 */
183 bool Remove(Tag& tag);
184 /**
185 * Replace the value of a tag.
186 *
187 * @param [in] tag The tag type to replace. To get the old
188 * value of the tag, use #Peek first.
189 * @returns True if \pname{tag} is found, false otherwise.
190 * If \pname{tag} wasn't found, Add is performed instead (so
191 * the list is guaranteed to have the new tag value either way).
192 */
193 bool Replace(Tag& tag);
194 /**
195 * Find a tag and return its value.
196 *
197 * @param [in,out] tag The tag type to find. If found,
198 * \pname{tag} is set to the value of the tag found.
199 * @returns True if \pname{tag} is found, false otherwise.
200 */
201 bool Peek(Tag& tag) const;
202 /**
203 * Remove all tags from this list (up to the first merge).
204 */
205 inline void RemoveAll();
206 /**
207 * @returns pointer to head of tag list
208 */
209 const PacketTagList::TagData* Head() const;
210 /**
211 * Returns number of bytes required for packet serialization.
212 *
213 * @returns number of bytes required for packet serialization
214 */
216 /**
217 * Serialize the tag list into a byte buffer.
218 *
219 * @param [in,out] buffer The byte buffer to which the tag list will be serialized
220 * @param [in] maxSize Max The max size of the buffer for bounds checking
221 *
222 * @returns zero if complete tag list is not serialized
223 */
224 uint32_t Serialize(uint32_t* buffer, uint32_t maxSize) const;
225 /**
226 * Deserialize tag list from the provided buffer.
227 *
228 * @param [in] buffer The buffer to read from.
229 * @param [in] size The number of bytes to deserialize.
230 *
231 * @returns zero if complete tag list is not deserialized
232 */
233 uint32_t Deserialize(const uint32_t* buffer, uint32_t size);
234
235 private:
236 /**
237 * Allocate and construct a TagData struct, sizing the data area
238 * large enough to serialize dataSize bytes from a Tag.
239 *
240 * @param [in] dataSize The serialized size of the Tag.
241 * @returns The newly constructed TagData object.
242 */
243 static TagData* CreateTagData(size_t dataSize);
244
245 /**
246 * Typedef of method function pointer for copy-on-write operations
247 *
248 * @param [in] tag The tag type to operate on.
249 * @param [in] preMerge True if \pname{tag} was found before the first merge,
250 * false otherwise.
251 * @param [in] cur Pointer to the tag.
252 * @param [in] prevNext Pointer to the struct TagData.next pointer
253 * pointing to \pname{cur}.
254 * @returns True if operation successful, false otherwise
255 */
256 typedef bool (PacketTagList::*COWWriter)(Tag& tag,
257 bool preMerge,
258 TagData* cur,
259 TagData** prevNext);
260 /**
261 * Traverse the list implementing copy-on-write, using \pname{Writer}.
262 *
263 * @param [in] tag The tag type to operate on.
264 * @param [in] Writer The copy-on-write function to use.
265 * @returns True if \pname{tag} found, false otherwise.
266 */
267 bool COWTraverse(Tag& tag, PacketTagList::COWWriter Writer);
268 /**
269 * Copy-on-write implementing Remove.
270 *
271 * @param [in] tag The target tag type to remove.
272 * @param [in] preMerge True if \pname{tag} was found before the first merge,
273 * false otherwise.
274 * @param [in] cur Pointer to the tag.
275 * @param [in] prevNext Pointer to the struct TagData.next pointer
276 * pointing to \pname{cur}.
277 * @returns True, since tag will definitely be removed.
278 */
279 bool RemoveWriter(Tag& tag, bool preMerge, TagData* cur, TagData** prevNext);
280 /**
281 * Copy-on-write implementing Replace
282 *
283 * @param [in] tag The target tag type to replace
284 * @param [in] preMerge True if \pname{tag} was found before the first merge,
285 * false otherwise.
286 * @param [in] cur Pointer to the tag
287 * @param [in] prevNext Pointer to the struct TagData.next pointer
288 * pointing to \pname{cur}.
289 * @returns True, since tag value will definitely be replaced.
290 */
291 bool ReplaceWriter(Tag& tag, bool preMerge, TagData* cur, TagData** prevNext);
292
293 /**
294 * Pointer to first \ref TagData on the list
295 */
297};
298
299} // namespace ns3
300
301/****************************************************
302 * Implementation of inline methods for performance
303 ****************************************************/
304
305namespace ns3
306{
307
309 : m_next()
310{
311}
312
314 : m_next(o.m_next)
315{
316 if (m_next != nullptr)
317 {
318 m_next->count++;
319 }
320}
321
324{
325 // self assignment
326 if (m_next == o.m_next)
327 {
328 return *this;
329 }
330 RemoveAll();
331 m_next = o.m_next;
332 if (m_next != nullptr)
333 {
334 m_next->count++;
335 }
336 return *this;
337}
338
343
344void
346{
347 TagData* prev = nullptr;
348 for (TagData* cur = m_next; cur != nullptr; cur = cur->next)
349 {
350 cur->count--;
351 if (cur->count > 0)
352 {
353 break;
354 }
355 if (prev != nullptr)
356 {
357 prev->~TagData();
358 std::free(prev);
359 }
360 prev = cur;
361 }
362 if (prev != nullptr)
363 {
364 prev->~TagData();
365 std::free(prev);
366 }
367 m_next = nullptr;
368}
369
370} // namespace ns3
371
372#endif /* PACKET_TAG_LIST_H */
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.
void RemoveAll()
Remove all tags from this list (up to the first merge).
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
PacketTagList()
Create a new PacketTagList.
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...
PacketTagList & operator=(const PacketTagList &o)
Assignment.
~PacketTagList()
Destructor.
bool(PacketTagList::* COWWriter)(Tag &tag, bool preMerge, TagData *cur, TagData **prevNext)
Typedef of method function pointer for copy-on-write operations.
tag a set of bytes in a packet
Definition tag.h:28
a unique identifier for an interface.
Definition type-id.h:48
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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.
uint32_t prev