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