4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 /** \mainpage Defining and using a new 'libPacket' Packet Type
25 This howto will introduce the facilities needed to define a new packet type. As example, the
26 \c GREPacket type is defined.
31 \section howto_newpacket_overview Overview
33 How is a new packet type defined? Or more basically: How are packets defined in the packet
36 In the packet library, there are two basic packet representations: There is the generic packet
37 senf::Packet. This representation does not know anything about the type of packet or any fields
38 or properties. It really only is a bunch of bytes. Possibly there is a preceding packet (header)
39 or a following one, but that is all, a senf::Packet knows.
41 However, this is not all. There is a second representation: senf::ConcretePacket. This
42 representation derives from senf::Packet and adds information about the packet type: Which
43 fields it has, maybe some invariants or packet specific operations and so on. This howto is
44 concerned with this representation.
46 A concrete packet type in senf provides a lot of detailed information about a specific type of
48 \li It provides access to the packets fields
49 \li It may provide additional packet specific functions (e.g. calculating or validating a
51 \li It provides information on the nesting of packets
52 \li It implements packet invariants
54 To define a new packet type, we need to implement to classes which together provide all this
56 \li a \e parser (a class derived from senf::PacketParserBase). This class defines the data
57 fields of the packet header and may provide also additional packet specific functionality.
58 \li a \e packet \e type (a class derived from senf::PacketTypeBase). This class defines, how
59 packets are nested and how to initialize and maintain invariants.
61 This howto will introduce how to define these classes using GRE as an example.
63 \section howto_newpacket_gre GRE Introduction
65 Before we start with the implementation, we begin with introducing the GRE packet. We will need
66 this information later in the implementation. Some decisions can also be taken now by just
67 looking at the packet specification:
68 \li What kind of parser is needed for this packet type (fixed size or variable sized).
69 \li Whether the packet has another packet as payload (a nested packet) and how the type of this
70 payload is found (whether a registry is used and if yes, which).
72 The GRE packet is defined in <a href="http://tools.ietf.org/html/rfc2784">RFC 2784</a>. In
73 Section 2.1 we find the header layout:
76 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
77 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 |C| Reserved0 | Ver | Protocol Type |
79 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80 | Checksum (optional) | Reserved1 (Optional) |
81 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84 This header is followed by the payload data.
86 Using this protocol definition, we can decide the first important question: Whether the packet
87 header is fixed size or dynamically sized. As we see above, the header incorporates optional
88 fields. Therefore it must be dynamically sized. The RFC further details, that if the \a Checksum
89 \a Present bit \a C is set, both \a Checksum and \a Reserved1 are present, otherwise they must
92 Another information we take from the RFC is, that the \a Protocol \a Type is used to define the
93 type of payload which directly follows the GRE header. This value is an <a
94 href="http://www.iana.org/assignments/ethernet-numbers">ETHERTYPE</a> value. To allow the packet
95 library to automatically parse the GRE payload data, we need to tell the packet library which
96 ETHERTYPE represents which packet type. This association already exists in form of the
97 senf::EtherTypes registry. Our GRE packet will therefore utilize this registry.
99 To summarize, we have gathered the following information:
101 \li The GRE packet header is a dynamically sized header.
102 \li The GRE packet header utilizes the senf::EtherTypes registry for next-header selection
105 \section howto_newpacket_parser Implementing the packet parser
107 The next step in creating a new packet type is to implement the parser. The parser is
108 responsible for turning a bunch of bytes into an interpreted header with specific fields. A
109 parser instance is constructed with an iterator (pointer) to the first byte to be interpreted
110 (the first byte of the packet data) and provides member functions to access the header
111 fields. You can implement these members manually but the SENF library provides a large set of
112 helper macros which simplify this task considerably.
114 \subsection howto_newpacket_parser_skeleton The PacketParser skeleton
117 #include <senf/Packets.hh>
119 struct GREPacketParser : public senf::PacketParserBase
121 # include SENF_PARSER()
125 SENF_PARSER_FINALIZE(GREPacketParser);
129 This is the standard skeleton of any parser class: We need to inherit senf::PacketParserBase and
130 start out by including either \ref SENF_PARSER() or \ref SENF_FIXED_PARSER(). Which, depends on
131 whether we define a fixed size or a dynamically sized parser. As \c GREPacketParser is
132 dynamically sized, we include \ref SENF_PARSER().
134 The following section will define all the fields. We will come back to this later.
136 After the fields are defined, we need to call the \ref SENF_PARSER_FINALIZE() macro to close of
137 the parser definition. This call takes the name of the parser being defined as it's sole
140 This is already a valid parser, albeit not a very usable one since it defines no fields. We now
141 go back to define the parser fields and begin with the simple part: Those fields which are
145 \subsection howto_newpacket_parser_simple Simple field definitions
147 Packet parser fields are defined utilizing special \ref packetpasermacros. We take the fields
148 directly from the definition of the packet type we want to implement (here the GRE RFC). In the
149 case of GRE we might come up with:
152 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
153 SENF_PARSER_SKIP_BITS ( 12 );
154 SENF_PARSER_BITFIELD ( version, 3, unsigned );
155 SENF_PARSER_BITFIELD ( protocolType, 16, unsigned );
158 This is a correct \c GREPacket header definition but we can optimize a little bit: Since the \a
159 protocolType field is aligned on a byte boundary, instead of defining it as a bitfield, we can
160 define it as a UInt16 field:
163 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
164 SENF_PARSER_SKIP_BITS ( 12 );
165 SENF_PARSER_BITFIELD ( version, 3, unsigned );
166 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
169 Whereas \ref SENF_PARSER_BITFIELD can define only bit-fields, \ref SENF_PARSER_FIELD can define
170 almost arbitrary field types. The type is specified by passing the name of another parser to
171 \ref SENF_PARSER_FIELD.
173 It is important to understand, that the accessors do \e not return the parsed field value. They
174 return another \e parser which is used to further interpret the value. This is the inherent
175 recursive nature of the SENF packet parsers. This allows to define wildly complex header formats
176 if needed. Of course, at some point we need the real value. This is, what the so called
177 <em>value parsers</em> do: They interpret some bytes or bits and return the value of that field
178 (not a parser). Examples are the bitfield parsers returned by the accessors generated by
179 SENF_PARSER_BITFIELD (like senf::UIntFieldParser) or the senf::UInt16Parser.
181 What happens in the above macros? Most of the macros define an accessor for a specific field: \a
182 checksumPresent() or \a protocolType(). They also manage a <em>current Offset</em>. This value
183 is advanced according to the field size whenever a new field is defined (and since this parser
184 is defined as a dynamically sized parser, this offset is not a constant, it is an expression
185 which calculates the offset of a field depending on the preceding data).
188 \subsection howto_newpacket_parser_variant Defining optional fields: The 'variant' parser
190 Until now, the parser is very simple, it could have been defined as a fixed size parser. Here we
191 will now explain, how to define optional fields. The same facilities are used to define
192 either/or fields or field collections.
194 In the special case of GRE< there are two fields which need to be disabled/enabled together. We
195 first define an additional sub-parser which combines those two fields. After this parser is
196 defined, we can use \ref SENF_PARSER_VARIANT() to add this parser as an optional parser to the
200 struct GREPacketParser_OptFields : public senf::PacketParserBase
202 # include SENF_FIXED_PARSER()
204 SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
205 SENF_PARSER_SKIP ( 2 );
207 SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
211 This parser only parses the two optional fields of which the reserved field is just skipped. The
212 parser this time is a fixed size parser. We can now use this parser to continue the \c
213 GREPacketParser implementation:
216 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
217 SENF_PARSER_SKIP_BITS ( 12 );
218 SENF_PARSER_BITFIELD ( version, 3, unsigned );
220 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
222 SENF_PARSER_VARIANT ( optionalFields, checksumPresent,
223 (senf::VoidPacketParser)
224 (GREPacketParser_OptFields) );
227 For a variant parser, two things need to be specified: A selector and a list of variant
228 parsers. The selector is another parser field which is used to decide, which variant to
229 choose. In this simple case, the field must be an unsigned integer (more precisely a value
230 parser which returns a value which is implicitly convertible to \c unsigned). This value is used
231 as index into the list of variant types. So in our case, 0 is associated with
232 senf::VoidPacketParser whereas 1 is associated with \c
233 GREPacketParser_OptFields. (senf::VoidPacketParser is a special empty parser which is used in a
234 Variant to denote cases in which the variant parser should not parse anything)
236 This parser will work, it is however not very safe and not very usable. If \a p is a
237 GREPacketParser instance, than we would access the fields via:
239 p.checksumPresent() = true;
241 p.protocolType() = 0x86dd;
242 p.optionalFields().get<1>().checksum() = 12345u;
245 This code has two problems:
246 \li accessing the checksum field is quite unwieldy
247 \li changing the checksumPresent() value will break the parser
249 The reason for the second problem lies in the fact, that the variant parser needs to be informed
250 whenever the selector (here \a checksumPresent) is changed since the variant parser must ensure,
251 that the header data stays consistent. In this example, whenever the checksumPresent field is
252 enabled, the variant parser needs to insert additional 4 bytes of data and remove those bytes,
253 when the checksumPresent field is disabled.
256 \subsection howto_newpacket_parser_fixvariant Fixing access by providing custom accessor members
258 The problems found above will happen whenever we use variant parsers and will often occur with
259 other complex parsers too (most \ref parsercollection reference some field external to
260 themselves and don't like it at all, if that value is changed without them knowing about
261 it). There may often also be other reasons to restrict access to a field: The field may be set
262 automatically or may be calculated from other values (how to do this, we'll see later).
264 In all these cases we will want to disallow the user of the packet to change the value while
265 still allowing him to read the value. To do this, we can mark \e value fields as read-only:
268 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
271 Value fields are fields, which return a simple value and not a complex sub-parser (this are
272 bit-fields, the integer parsers and also some additional parsers like those parsing network
275 In this case however, we still want to allow the user to change the field value, albeit not
276 directly. We will need to go through the collection parser, in this case the variant. Since the
277 variant syntax to change the currently active variant is not very favorable, we provide nice
278 helper members for this:
281 void enableChecksum() const { optionalFields_().init<1>(); }
282 void disableChecksum() const { optionalFields_().init<0>(); }
285 By changing the collection we automatically change the field, this collection references. Now we
286 only need to provide an additional \a checksum member to hide the complex variant access syntax
287 from the user. And since now all variant access is via specialized members, we can hide the
288 variant field completely from the user:
291 SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
292 (senf::VoidPacketParser)
293 (GREPacketParser_OptFields) );
295 GREPacketParser_OptFields::checksum_t checksum() const
296 { return optionalFields_().get<1>().checksum(); }
299 As we can see here, we have used the <em>name</em><code>_t</code> typedef which is available for
300 all fields to provide the return value for our accessor member.
302 The \c GREPacketParser is now simple and safe to use. The only responsibility of the user now is to
303 only access \a checksum() if the \a checksumPresent() field is set. Otherwise, the behavior is
304 undefined (in debug builds, the parser will terminate the application with an assert).
307 \subsection howto_newpacket_parser_add Providing additional functionality
309 We have now implemented parsing all the header fields. However, often packets would benefit from
310 additional functionality. In the case of GRE, this could be a function to calculate the checksum
311 value if it is enabled. Defining this member will also show, how to safely access the raw packet
312 data from a parser member.
315 #include <senf/Utils/IpChecksum.hh>
317 checksum_t::value_type calculateChecksum() const
319 if (!checksumEnabled())
323 cs.feed( i(), i(4) );
324 // Skip even number of 0 bytes (the 2 bytes checksum field)
325 // cs.feed(0); cs.feed(0);
326 cs.feed( i(6), data().end() );
332 This code just implements what is defined in the RFC: The checksum covers the complete GRE
333 packet including it's header with the checksum field temporarily set to 0. Instead of really
334 changing the checksum field we manually pass the correct data to \a cs.
336 We use the special <tt>i(</tt><i>offset</i><tt>)</tt> helper to get iterators \a offset number
337 of bytes into the data. This helper has the additional benefit of range-checking the returned
338 iterator and is thereby safe from errors due to truncated packets: If the offset is out of
339 range, a TruncatedPacketException will be thrown.
341 The \a data() function on the other hand returns a reference to the complete data container of
342 the packet under inspection (the GRE packet in this case). Access to \a data() should be
343 restricted as much as possible. It is safe when defining new packet parsers (parsers, which
344 parser a complete packet like GREPacketParser). It's usage from sub parsers (like
345 GREPacketParser_OptFields or even senf::UInt16Parser) would be much more arcane and should be
349 \subsection howto_newpacket_parser_final The complete GREPacketParser implementation
351 So this is now the complete implementation of the \c GREPacketParser:
354 #include <senf/Packets.hh>
356 struct GREPacketParser_OptFields : public senf::PacketParserBase
358 # include SENF_FIXED_PARSER()
360 SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
361 SENF_PARSER_SKIP ( 2 );
363 SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
366 struct GREPacketParser : public senf::PacketParserBase
368 # include SENF_PARSER()
370 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
371 SENF_PARSER_SKIP_BITS ( 12 );
372 SENF_PARSER_BITFIELD ( version, 3, unsigned );
374 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
376 SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
377 (senf::VoidPacketParser)
378 (GREPacketParser_OptFields) );
380 GREPacketParser_OptFields::checksum_t checksum() const
381 { return optionalFields_().get<1>().checksum(); }
383 void enableChecksum() const { optionalFields_().init<1>(); }
384 void disableChecksum() const { optionalFields_().init<0>(); }
386 SENF_PARSER_FINALIZE(GREPacketParser);
388 checksum_t::value_type calculateChecksum() const;
391 // In the implementation (.cc) file:
393 #include <senf/Utils/IpChecksum.hh>
395 GREPacketParser::checksum_t::value_type GREPacketParser::calculateChecksum() const
397 if (!checksumEnabled())
402 cs.feed( i(), i()+4 );
403 // Skip even number of 0 bytes (the 2 bytes checksum field)
404 // cs.feed(0); cs.feed(0);
405 cs.feed( i()+6, data().end() );
412 \section howto_newpacket_type Defining the packet type
414 After defining the packet parser, the <em>packet type</em> must be defined. This class is used
415 as a policy and collects all the information necessary to be known about the packet type.
417 The <em>packet type</em> class is \e never instantiated. It has only typedef, constants or
420 \subsection howto_newpacket_type_skeleton The packet type skeleton
422 For every type of packet, the <em>packet type</em> class will look roughly the same. If the
423 packet utilizes a registry and is not hopelessly complex, the packet type will almost always
427 #include <senf/Packets.hh>
430 : public senf::PacketTypeBase,
431 public senf::PacketTypeMixin<GREPacketType, EtherTypes>
433 typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
434 typedef senf::ConcretePacket<GREPacketType> packet;
435 typedef senf::GREPacketParser parser;
437 using mixin::nextPacketRange;
438 using mixin::nextPacketType;
440 using mixin::initSize;
442 // Define members here
446 We note, that it derives from two classes: senf::PacketTypeBase and
447 senf::PacketTypeMixin. senf::PacketTypeBase must be inherited by every packet type class. the
448 senf::PacketTypeMixin provides default implementations for some members which are useful for
449 most kinds of packets. If a packet type is very complex and these defaults don't work, the mixin
450 class can and should be left out. More on this (what the default members do exactly and when the
451 mixin can be used) can be found in the senf::PacketTypeMixin documentation.
453 Of the typedefs, only \a parser is mandatory. It defines the packet parser to use to interpret
454 this type of packet. \a mixin and \a packet are defined to simplify the following
455 definitions (More on \a packet and senf::ConcretePacket later).
457 The next block of statements imports all the default implementations provided by the mixin
460 \li \a nextPacketRange provides information about where the next packet lives within the GRE
462 \li \a nextPacketType provides the type of the next packet from information in the GRE packet.
463 \li \a init is called to initialize a new GRE packet. This call is forwarded to \c
464 GREPacketParser::init.
465 \li \a initSize is called to find the size of an empty (newly create) GRE packet. This is also
466 provided by GREPacketParser.
468 With these default implementations provided by the mixin, only a few additional members are
469 needed to complete the \c GREPacketType: \a nextPacketKey, \a finalize, and \a dump.
472 \subsection howto_newpacket_type_registry Utilizing the packet registry
474 A packet registry maps an arbitrary key value to a type of packet represented by a packet
475 factory instance. There may be any number of packet registries. When working with packet
476 registries, there are three separate steps:
477 \li Using the registry to tell the packet library, what type of packet to instantiate for the
479 \li Given a payload packet of some type, set the appropriate payload type field in the packet
480 header to the correct value (inverse of above).
481 \li Adding packets to the registry.
483 We want the GRE packet to utilize the senf::EtherTypes registry to find the type of packet
484 contained in the GRE payload. The details have already been taken care of by the
485 senf::PacketTypeMixin (it provides the \a nextPacketType member). However, to lookup the packet
486 in the registry, the mixin needs to know the key value. To this end, we implement \a
487 nextPacketKey(), which is very simple:
490 static key_t nextPacketKey(packet p) { return p->protocolType(); }
493 Since all \c GREPacketType members are static, they are passed the packet in question as an
494 argument. \a nextPacketKey() just needs to return the value of the correct packet field. And
495 since the \c packet type (as defined as a typedef) allows direct access to the packet parser
496 using the <tt>-></tt> operator, we can simply access that value.
498 The \c key_t return type is a typedef provided by the mixin class. It is taken from the type of
499 registry, in this case it is senf::EtherTypes::key_t (which is defined as a 16 bit unsigned
502 With this information, the packet library can now find out the type of packet needed to parse
503 the GRE payload -- as long as the \a protocolType() is registered with the senf::EtherTypes
504 registry. If this is not the case, the packet library will not try to interpret the payload, it
505 will return a senf::DataPacket.
507 One special case of GRE encapsulation occurs when layer 2 frames and especially ethernet frames
508 are carried in the GRE payload. The ETHERTYPE registry normally only contains layer 3 protocols
509 (like IP or IPX) however for this special case, the value 0x6558 has been added to the ETHERTYPE
510 registry. So we need to add this value to inform the packet library to parse the payload as an
511 ethernet packet if the \a protocolType() is 0x6558. This happens in the implementation file (the
515 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
517 SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
520 This macro registers the value 0x6558 in the senf::EtherTypes registry and associates it with
521 the packet type senf::EthernetPacket. This macro declares an anonymous static variable, it
522 therefore must always be placed in the implementation file and \e never in an include file.
524 Additionally, we want the GRE packet to be parsed when present as an IP payload. Therefore we
525 additionally need to register GRE in the senf::IpTypes registry. Looking at the <a
526 href="http://www.iana.org/assignments/protocol-numbers">IP protocol numbers</a>, we find that
527 GRE has been assigned the value 47:
530 #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
532 SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
535 But wait -- what is \c GREPacket ? This question is answered a few section further down.
537 The last thing we need to do is, we need to set the \a protocolType() field to the correct value
538 when packets are newly created or changed. This is done within \a finalize:
541 static void finalize(packet p) { p->protocolType() << key(p.next(senf::nothrow)); }
544 The \c key() function is provided by the mixin class: It will lookup the \e type of a packet in
545 the registry and return that packets key in the registry. If the key cannot be found, the return
546 value is such that the assignment is effectively skipped.
549 \subsection howto_newpacket_type_invariants Providing packet invariants
551 Many packets have some invariants that must hold: The payload size must be equal to some field,
552 a checksum must match and so on. When packets are newly created or changed, these invariants
553 have to be updated to be correct. This is the responsibility of the \a finalize() member.
556 static void finalize(packet p)
558 p->protocolType() << key(p.next(senf::nothrow));
559 if (p->checksumPresent())
560 p->checksum() << p->calculateChecksum();
564 We already used finalize above to set the \a protocolType() field. Now we add code to update the
565 \a checksum() field if present (this always needs to be done last since the checksum depends on
566 the other field values).
568 Here we are using the more generic parser assignment expressed using the \c << operator. This
569 operator in the most cases works like an ordinary assignment, however it can also be used to
570 assign parsers to each other efficiently and it supports 'optional values' (as provided by <a
571 href="http://www.boost.org/libs/optional/doc/optional.html">Boost.Optional</a> and as returned
575 \subsection howto_newpacket_type_dump Writing out a complete packet: The 'dump()' member
577 For diagnostic purposes, every packet should provide a meaningful \a dump() member which writes
578 out the complete packet. This member is simple to implement and is often very helpful when
579 tracking down problems.
582 #include <boost/io/ios_state.hpp>
584 static void dump(packet p, std::ostream & os)
586 boost::io::ios_all_saver ias(os);
587 os << "General Routing Encapsulation:\n"
588 << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n"
589 << " version : " << p->version() << "\n"
590 << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0')
591 << p->protocolType() << "\n";
592 if (p->checksumPresent())
593 os << " checksum : 0x" << std::hex << std::setw(4)
594 << std::setfill('0') << p->checksum() << "\n";
598 This member is quite straight forward. We should try to adhere to the formating standard shown
599 above: The first line should be the type of packet/header being dumped followed by one line for
600 each protocol field. The colon's should be aligned at column 33 with the field name indented by
603 The \c boost::ios_all_saver is just used to ensure, that the stream formatting state is restored
604 correctly at the end of the method. An instance of this type will save the stream state when
605 constructed and will restore that state when destructed.
607 \subsection howto_newpacket_type_final Final touches
609 The \c GREPacket implementation is now almost complete. The only thing missing is the \c
610 GREPacket itself. \c GREPacket is just a typedef for a specific senf::ConcretePacket template
611 instantiation. Here the complete GREPacket definition:
614 #include <senf/Packets.hh>
617 : public senf::PacketTypeBase,
618 public senf::PacketTypeMixin<GREPacketType, EtherTypes>
620 typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
621 typedef senf::ConcretePacket<GREPacketType> packet;
622 typedef senf::GREPacketParser parser;
624 using mixin::nextPacketRange;
625 using mixin::nextPacketType;
627 using mixin::initSize;
629 static key_t nextPacketKey(packet p) { return p->protocolType(); }
631 static void finalize(packet p) {
632 p->protocolType() << key(p.next(senf::nothrow));
633 if (p->checksumPresent()) p->checksum() << p->calculateChecksum();
636 static void dump(packet p, std::ostream & os);
639 typedef GREPacketType::packet GREPacket;
641 // In the implementation (.cc) file:
643 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
644 #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
646 SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
647 SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
649 void GREPacketType::dump(packet p, std::ostream & os)
651 boost::io::ios_all_saver ias(os);
652 os << "General Routing Encapsulation:\n"
653 << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n"
654 << " version : " << p->version() << "\n"
655 << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0')
656 << p->protocolType() << "\n";
657 if (p->checksumPresent())
658 os << " checksum : 0x" << std::hex << std::setw(4)
659 << std::setfill('0') << p->checksum() << "\n";
664 \section howto_newpacket_advanced Going further
666 \subsection howto_newpacket_advanced_valid Checking the GRE packet for validity
668 We now know how to define packets, but there is more. In this section we will explore the
669 features available to make the packet chaining more flexible. We will show, how to implement
670 more complex logic than simple registry lookup to find the nested packet (the payload) type.
672 In our concrete example, reading the RFC we find there are some restrictions which a GRE packet
673 needs to obey to be considered valid. If the packet is not valid it cannot be parsed and should
674 be dropped. We can't drop it here but if the packet is invalid, we certainly must refrain from
675 trying to parser any payload since we cannot assume the packet to have the format we assume our
678 There are two conditions defined in the RFC which render a GRE packet invalid: If one of the \a
679 reserved0() fields first 5 bits is set or if the version is not 0. We will add a \a valid()
680 check to the parser and utilize this check in the packet type.
682 So first lets update the parser. We will need to change the fields a little bit so we have
683 access to the first 5 bits of \a reserved0. We therefore replace the first three field
687 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
688 SENF_PARSER_PRIVATE_BITFIELD ( reserved0_5bits_, 5, unsigned );
689 SENF_PARSER_SKIP_BITS ( 7 );
690 SENF_PARSER_BITFIELD_RO ( version, 3, unsigned );
693 We have added an additional private bitfield \a reserved0_5bits_() and we made the \a version()
696 We will now add a simple additional member to the parser:
699 bool valid() const { return version() == 0 && reserved0_5bits_() == 0; }
702 I think, this is quite straight forward: \a valid() will just check the restrictions as defined
705 Now to the packet type. We want to refrain from parsing the payload if the packet is
706 invalid. This is important: If the packet is not valid, we have no idea, whether the payload is
707 what we surmise it to be (if any of the \a reserved0_5bits_() are set, the packet is from an
708 older GRE RFC and the header is quite a bit longer so the payload will be incorrect).
710 So we need to change the logic which is used by the packet library to find the type of the next
711 packet. We have two ways to do this: We keep using the default \c nextPacketType()
712 implementation as provided by the senf::PacketTypeMixin and have our \a nextPacketKey()
713 implementation return a key value which is guaranteed never to be registered in the registry.
715 The more flexible possibility is implementing \c nextPacketType() ourselves. In this case, the
716 first method would suffice, but we will choose to go the second route to show how to write the
717 \c nextPacketType() member. We therefore remove the \c using declaration of \c nextPacketType()
718 and also remove the \a nextPacketKey() implementation. Instead we add the following to the
722 // disabled: using mixin::nextPacketType;
724 factory_t nextPacketType(packet p) { return p->valid() ? lookup(p->protocolType()) : no_factory(); }
727 As we see, this is still quite simple. \c factory_t is provided by senf::PacketTypeBase. For our
728 purpose it is an opaque type which somehow enables the packet library to create a new packet of
729 a specified packet type. The \c factory_t has a special value, \c no_factory() which stands for
730 the absence of any concrete factory. In a boolean context this (and only this) \c factory_t
731 value tests \c false.
733 The \c lookup() member is provided by the senf::PacketTypeMixin. It looks up the key passed as
734 argument in the registry and returns the factory or \c no_factory(), if the key was not found in
737 In this case this is all. But let's elaborate on this example. What if we need to return some
738 specific factory from \a nextPacketType(), e.g. what, if we want to handle the case of
739 transparent ethernet bridging explicitly instead of registering the value in the
740 senf::EtherTypes registry ? Here one way to do this:
743 factory_t nextPacketType(packet p) {
745 if (p->protocolType() == 0x6558) return senf::EthernetPacket::factory();
746 else return lookup(p->protocolType());
748 else return no_factory();
752 As can be seen above, every packet type has a (static) \a factory() member which returns the
753 factory for this type of packet.
756 \subsection howto_newpacket_advanced_init Non-trivial packet initialization
758 Every packet when created is automatically initialized with 0 bytes (all data bytes will be
759 0). In the case of GRE this is enough. But other packets will need other more complex
760 initialization to be performed.
762 Lets just for the sake of experiment assume, the GRE packet would have to set \a version() to 1
763 not 0. In this case, the default initialization would not suffice. It is however very simple to
764 explicitly initialize the packet. The initialization happens within the parser. We just add
767 SENF_PARSER_INIT() { version_() << 1u; }
770 to \c GREPacketParser. For every read-only defined field, the macros automatically define a \e
771 private read-write accessor which may be used internally. This read-write accessor is used here
772 to initialize the value.
775 \section howto_newpacket_final The ultimate GRE packet implementation completed
777 So here we now have \c GREPacket finally complete in all it's glory. First the header file \c
781 #ifndef HH_GREPacket_
782 #define HH_GREPacket_
784 #include <senf/Packets.hh>
786 struct GREPacketParser_OptFields : public senf::PacketParserBase
788 # include SENF_FIXED_PARSER()
790 SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
791 SENF_PARSER_SKIP ( 2 );
793 SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
796 struct GREPacketParser : public senf::PacketParserBase
798 # include SENF_PARSER()
800 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
801 SENF_PARSER_PRIVATE_BITFIELD ( reserved0_5bits_, 5, unsigned );
802 SENF_PARSER_SKIP_BITS ( 7 );
803 SENF_PARSER_BITFIELD_RO ( version, 3, unsigned );
805 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
807 SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
808 (senf::VoidPacketParser)
809 (GREPacketParser_OptFields) );
811 typedef version__t version_t;
812 version_t::value_type version() const { return version_(); }
814 bool valid() const { return version() == 0 && reserved0_5bits_() == 0; }
816 typedef GREPacketParser_OptFields::checksum_t checksum_t;
817 checksum_t checksum() const
818 { return optionalFields_().get<1>().checksum(); }
820 void enableChecksum() const { optionalFields_().init<1>(); }
821 void disableChecksum() const { optionalFields_().init<0>(); }
823 SENF_PARSER_FINALIZE(GREPacketParser);
825 checksum_t::value_type calculateChecksum() const;
829 : public senf::PacketTypeBase,
830 public senf::PacketTypeMixin<GREPacketType, EtherTypes>
832 typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
833 typedef senf::ConcretePacket<GREPacketType> packet;
834 typedef senf::GREPacketParser parser;
836 using mixin::nextPacketRange;
838 using mixin::initSize;
840 factory_t nextPacketType(packet p)
841 { return p->valid() ? lookup(p->protocolType()) : no_factory(); }
843 static void finalize(packet p) {
844 p->protocolType() << key(p.next(senf::nothrow));
845 if (p->checksumPresent()) p->checksum() << p->calculateChecksum();
848 static void dump(packet p, std::ostream & os);
851 typedef GREPacketType::packet GREPacket;
856 And the implementation file \c GREPacket.cc:
859 #include "GREPacket.hh"
860 #include <senf/Utils/IpChecksum.hh>
861 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
862 #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
864 SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
865 SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
867 GREPacketParser::checksum_t::value_type GREPacketParser::calculateChecksum() const
869 if (!checksumEnabled())
874 cs.feed( i(), i()+4 );
875 // Skip even number of 0 bytes (the 2 bytes checksum field)
876 // cs.feed(0); cs.feed(0);
877 cs.feed( i()+6, data().end() );
882 void GREPacketType::dump(packet p, std::ostream & os)
884 boost::io::ios_all_saver ias(os);
885 os << "General Routing Encapsulation:\n"
886 << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n"
887 << " version : " << p->version() << "\n"
888 << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0')
889 << p->protocolType() << "\n";
890 if (p->checksumPresent())
891 os << " checksum : 0x" << std::hex << std::setw(4)
892 << std::setfill('0') << p->checksum() << "\n";
897 \section howto_newpacket_using Using the newly created GRE packet type
899 The GRE packet is now fully integrated into the packet library framework. For example, we can
900 read GRE packets from a raw INet socket and forward decapsulated Ethernet frames to a packet
905 #include <senf/Packets.hh>
906 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
907 #include <senf/Socket/Protocols/INet/RawINetProtocol.hh>
908 #include <senf/Socket/Protocols/Raw/PacketSocketHandle.hh>
909 #include "GREPacket.hh"
911 int main(int, char const **)
913 senf::RawV6ClientSocketHandle isock (47u); // 47 = Read GRE packets
914 senf::PacketSocketHandle osock;
918 GREPacket gre (GREPacket::create(senf::noinit));
919 isock.read(gre.data(),0u);
920 if (gre->checksumPresent() && gre->checksum() != gre->calculateChecksum())
921 throw InvalidPacketChainException();
922 osock.write(gre.next<EthernetPacket>().data())
924 catch (senf::TruncatedPacketException & ex) {
925 std::cerr << "Malformed packet dropped\n";
927 catch (senf::InvalidPacketChainException & ex) {
928 std::cerr << "Invalid GRE packet dropped\n";
934 Or we can do the opposite: Read ethernet packets from a \c tap device and send them out GRE
939 #include <senf/Packets.hh>
940 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
941 #include <senf/Socket/Protocols/INet/RawINetProtocol.hh>
942 #include <senf/Socket/Protocols/Raw/TunTapSocketHandle.hh>
943 #include "GREPacket.hh"
945 int main(int argc, char const ** argv)
948 std::cerr << "Usage: " << argv[0] << " <tunnel endpoint>\n";
952 senf::TapSocketHandle tap ("tap0");
953 senf::ConnectedRawV6ClientSocketHandle osock (47u, senf::INet6SocketAddress(argv[1]));
956 senf::EthernetPacket eth (senf::EthernetPacket::create(senf::noinit));
957 isock.read(eth.data(),0u);
958 GREPacket gre (senf::GREPacket::createBefore(eth));
960 osock.write(gre.data());
966 \section howto_newpacket_further Further reading
968 Lets start with references to the important API's (Use the <i>List of all members</i> link to
969 get the complete API of one of the classes and templates):
971 <table class="senf fixedcolumn">
973 <tr><td>senf::ConcretePacket</td> <td>this is the API provided by the packet handles.</td></tr>
975 <tr><td>senf::PacketData</td> <td>this API provides raw data access accessible via the handles
976 'data' member.</td></tr>
978 <tr><td>senf::PacketParserBase</td> <td>this is the generic parser API. This API is accessible
979 via the packets \c -> operator or via the sub-parsers returned by the field accessors.</td></tr>
983 When implementing new packet's, the following information will be helpful:
985 <table class="senf fixedcolumn">
987 <tr><td>senf::PacketTypeBase</td> <td>here you find a description of the members which need to
988 be implemented to provide a 'packet type'. Most of these members will normally be provided by
989 the mixin helper.</td></tr>
991 <tr><td>senf::PacketTypeMixin</td> <td>here you find all about the packet type mixin and how to
994 <tr><td>\ref packetparser</td> <td>This section describes the packet parser facility.</td></tr>
996 <tr><td>\link packetparsermacros Packet parser macros\endlink</td> <td>A complete list and
997 documentation of all the packet parser macros.</td></tr>
999 <tr><td>\ref parseint, \n \ref parsecollection</td> <td>There are several lists of available
1000 reusable packet parsers. However, these lists are not complete as there are other protocol
1001 specific reusable parsers (without claiming to be exhaustive: senf::INet4AddressParser,
1002 senf::INet6AddressParser, senf::MACAddressParser)</td></tr>
1012 // comment-column: 40
1013 // c-file-style: "senf"
1014 // indent-tabs-mode: nil
1015 // ispell-local-dictionary: "american"
1016 // compile-command: "scons -u doc"