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_start Getting started
33 Before starting with the implementation, we look at the specification of the GRE packet. This is
34 found in <a href="http://tools.ietf.org/html/rfc2784">RFC 2784</a> in Section 2.1:
37 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
38 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 |C| Reserved0 | Ver | Protocol Type |
40 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 | Checksum (optional) | Reserved1 (Optional) |
42 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 Using this protocol definition, we can decide the first important question: Whether the packet
46 header is fixed size or dynamically sized. As we see above, the header incorporates optional
47 fields. Therefore it must be dynamically sized. The RFC further details, that if the \a Checksum
48 \a Present bit \a C is set, both \a Checksum and \a Reserved1 are present, otherwise they must
51 Another information we take from the RFC is, that the \a Protocol \a Type is used to define the
52 type of payload which directly follows the GRE header. This value is an <a
53 href="http://www.iana.org/assignments/ethernet-numbers">ETHERTYPE</a> value. To allow the packet
54 library to automatically parse the GRE payload data, we need to tell the packet library which
55 ETHERTYPE represents which packet type. This association already exists in form of the
56 senf::EtherTypes registry. Our GRE packet will therefore utilize this registry.
58 To summarize, we have gathered the following information:
60 \li The GRE packet header is a dynamically sized header.
61 \li The GRE packet header utilizes the senf::EtherTypes registry for next-header selection
64 \section howto_newpacket_parser Implementing the GRE Parser
66 The next step in creating a new packet type is to implement the parser. The parser is
67 responsible for turning a bunch of bytes into an interpreted header with specific fields. The
68 parser will later be constructed with an iterator (pointer) to the first byte to be interpreted
69 as a GRE header and will provide member functions to access the header fields. You can implement
70 these members manually but the SENF library provides a large set of helper macros which simplify
71 this task considerably.
74 \subsection howto_newpacket_parser_skeleton The PacketParser skeleton
77 #include <senf/Packets.hh>
79 struct GREPacketParser : public senf::PacketParserBase
81 # include SENF_PARSER()
85 SENF_PARSER_FINALIZE(GREPacketParser);
89 This is the standard skeleton of any parser class: We need to inherit senf::PacketParserBase and
90 start out by including either \ref SENF_PARSER() or \ref SENF_FIXED_PARSER(). Which, depends on
91 whether we define a fixed size or a dynamically sized parser. As \c GREPacketParser is
92 dynamically sized, we include \ref SENF_PARSER().
94 After the fields are defined, we need to call the \ref SENF_PARSER_FINALIZE() macro to close of
95 the parser definition. This call takes the name of the parser being defined as it's sole
98 This is already a valid parser, albeit not a very usable one since it defines no fields. We now
99 go back to define the parser fields and begin with the simple part: Those fields which are
103 \subsection howto_newpacket_parser_simple Simple field definitions
106 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
107 SENF_PARSER_SKIP_BITS ( 12 );
108 SENF_PARSER_BITFIELD ( version, 3, unsigned );
109 SENF_PARSER_BITFIELD ( protocolType, 16, unsigned );
112 This is a direct transcript of the field definition above. There are quite a number of macros
113 which may be used to define fields. All these macros are documented in '\ref
116 This is a correct \c GREPacket header definition but we can optimize a little bit: Since the \a
117 protocolType field is aligned on a byte boundary, instead of defining it as a bitfield, we can
118 define it as a UInt16 field:
121 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
122 SENF_PARSER_SKIP_BITS ( 12 );
123 SENF_PARSER_BITFIELD ( version, 3, unsigned );
125 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
128 Whereas \ref SENF_PARSER_BITFIELD can define only bit-fields, \ref SENF_PARSER_FIELD can define
129 almost arbitrary field types. The type is specified by passing the name of another parser to
130 \ref SENF_PARSER_FIELD.
132 It is important to understand, that the accessors do \e not return the parsed field value. They
133 return another \e parser which is used to further interpret the value. This is the inherent
134 recursive nature of the SENF packet parsers. This allows to define wildly complex header formats
135 if needed. Of course, at some point we need the real value. This is, what the so called
136 <em>value parsers</em> do: They interpret some bytes or bits and return the value of that field
137 (not a parser). Examples are the bitfield parsers returned by the accessors generated by
138 SENF_PARSER_BITFIELD (like senf::UIntFieldParser) or the senf::UInt16Parser.
140 What happens in the above macros? Most of the macros define an accessor for a specific field: \a
141 checksumPresent() or \a protocolType(). They also manage a <em>current Offset</em>. This value
142 is advanced according to the field size whenever a new field is defined (and since this parser
143 is defined as a dynamically sized parser, this offset is not a constant, it is an expression
144 which calculates the offset of a field depending on the preceding data).
147 \subsection howto_newpacket_parser_variant Defining optional fields: The 'variant' parser
149 We now come to the optional fields. Since there are two fields which need to be disabled/enabled
150 together, we first need to define an additional sub-parser which combines those two
151 fields. After this parser is defined, we can use \ref SENF_PARSER_VARIANT() to add this parser
152 as an optional parser to the GRE header.
155 struct GREPacketParser_OptFields : public senf::PacketParserBase
157 # include SENF_FIXED_PARSER()
159 SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
160 SENF_PARSER_SKIP ( 2 );
162 SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
166 This parser only parses the two optional fields of which the reserved field is just skipped. The
167 parser this time is a fixed size parser. We can now use this parser to continue the \c GREPacketParser
171 SENF_PARSER_BITFIELD ( checksumPresent, 1, bool );
172 SENF_PARSER_SKIP_BITS ( 12 );
173 SENF_PARSER_BITFIELD ( version, 3, unsigned );
175 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
177 SENF_PARSER_VARIANT ( optionalFields, checksumPresent,
178 (senf::VoidPacketParser)
179 (GREPacketParser_OptFields) );
182 For a variant parser, two things need to be specified: A selector and a list of variant
183 parsers. The selector is another parser field which is used to decide, which variant to
184 choose. In this simple case, the field must be an unsigned integer (more precisely a value
185 parser which returns a value which is implicitly convertible to \c unsigned). This value is used
186 as index into the list of variant types. So in our case, 0 is associated with
187 senf::VoidPacketParser whereas 1 is associated with \c
188 GREPacketParser_OptFields. (senf::VoidPacketParser is a special empty parser which is used in a
189 Variant to denote cases in which the variant parser should not parse anything)
191 This parser will work, it is however not very safe and not very usable. If \a p is a GREPacketParser
192 instance, than we access the fields via:
194 p.checksumPresent() = true;
196 p.protocolType() = 0x86dd;
197 p.optionalFields().get<1>().checksum() = 12345u;
200 There are two problems here:
201 \li accessing the checksum field is quite unwieldy
202 \li changing the checksumPresent() value will break the parser
204 The reason for the second problem lies in the fact, that the variant parser needs to be informed
205 whenever the selector (here \a checksumPresent) is changed since the variant parser must ensure,
206 that the header data stays consistent. In this example, whenever the checksumPresent field is
207 enabled, the variant parser needs to insert additional 4 bytes of data and remove those bytes,
208 when the checksumPresent field is disabled.
211 \subsection howto_newpacket_parser_fixvariant Fixing access by providing custom accessor members
213 Since we don't want to allow the \a checksumPresent() field to be changed directly, we mark this
217 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
220 To change the \a checksumPresent() value, the variant parser provides special members to change
221 the currently selected variant:
224 p.optionalFields().init<0>();
225 p.optionalFields().init<1>();
228 These statements also change the selector field (in this case \a checksumPresent()) to the
229 correct value: The first statements switches to the first variant and therefore in this case
230 disables the checksum field. The second statement will switch to the second variant and enable
233 Again, these statements are relatively complex. So we complete the parser by providing simple
234 additional members which wrap these complicated calls. While doing this, we also mark the
235 variant as a private field so it is not directly accessible any more (since we now have the
236 additional helpers which are used to access the variant, we don't want anyone to mess around
240 SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
241 (senf::VoidPacketParser)
242 (GREPacketParser_OptFields) );
244 typedef GREPacketParser_OptFields::checksum_t checksum_t;
245 checksum_t checksum() const
246 { return optionalFields_().get<1>().checksum(); }
248 void enableChecksum() const { optionalFields_().init<1>(); }
249 void disableChecksum() const { optionalFields_().init<0>(); }
252 Above code has one other twist we need to discuss: the \a checksum_t typedef. This is added as a
253 convenience to the user of this parser. The \c SENF_PARSER_* macros which define a field all
254 define some additional symbols providing further information about the field. Of these
255 additional symbols, the most important is <em>field</em><code>_t</code>, which is the (parser)
256 type returned by the field. This helps to work with a parser in more complex situations
257 (e.g. when using \ref parsecollection) since it allows to access the parser type without exact
258 knowledge of this type (which may become quite complex if templates are involved) as long as the
259 field name is known. Since we provide an accessor for the \a checksum field, we also provide the
260 \a checksum_t typedef for this accessor.
262 The \c GREPacketParser is now simple and safe to use. The only responsibility of the user now is to
263 only access \a checksum() if the \a checksumPresent() field is set. Otherwise, the behavior is
264 undefined (in debug builds, the parser will terminate the application with an assert).
267 \subsection howto_newpacket_parser_add Providing additional functionality
269 The \c GREPacketParser is now complete. But we can do better: A packet parser is not restricted
270 to simply parsing data. Depending on the packet type, additional members can be arbitrarily
271 defined. In the case of \c GREPacket, we provide one additional member, \a calculateChecksum()
272 which does just that: It calculates the checksum of the GRE packet.
275 #include <senf/Utils/IpChecksum.hh>
277 checksum_t::value_type calculateChecksum() const
279 if (!checksumEnabled())
283 cs.feed( i(), i(4) );
284 // Skip even number of 0 bytes (the 2 bytes checksum field)
285 // cs.feed(0); cs.feed(0);
286 cs.feed( i(6), data().end() );
292 This code just implements what is defined in the RFC: The checksum covers the complete GRE
293 packet including it's header with the checksum field temporarily set to 0. Instead of really
294 changing the checksum field we manually pass the correct data to \a cs.
296 We use the special <tt>i(</tt><i>offset</i><tt>)</tt> helper to get iterators \a offset number
297 of bytes into the data. This helper has the additional benefit of range-checking the returned
298 iterator and thereby safe os from errors due to truncated packets: If the offset is out of
299 range, a TruncatedPacketException will be thrown.
301 In this code we utilize some additional information provided by senf::PacketParserBase. The \a
302 i() member returns an iterator to the first byte the parser is interpreting whereas \a data()
303 returns a reference to the packet data container for the packet being parsed. Access to \a
304 data() should be restricted as much as possible. It is safe when defining new packet parsers
305 (like GREPacketParser). It's usage from sub parsers (like GREPacketParser_OptFields or even
306 senf::UInt16Parser) would be much more arcane and should be avoided.
309 \subsection howto_newpacket_parser_final The complete GREPacketParser implementation
311 So this is now the complete implementation of the \c GREPacketParser:
314 #include <senf/Packets.hh>
316 struct GREPacketParser_OptFields : public senf::PacketParserBase
318 # include SENF_FIXED_PARSER()
320 SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
321 SENF_PARSER_SKIP ( 2 );
323 SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
326 struct GREPacketParser : public senf::PacketParserBase
328 # include SENF_PARSER()
330 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
331 SENF_PARSER_SKIP_BITS ( 12 );
332 SENF_PARSER_BITFIELD ( version, 3, unsigned );
334 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
336 SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
337 (senf::VoidPacketParser)
338 (GREPacketParser_OptFields) );
340 typedef GREPacketParser_OptFields::checksum_t checksum_t;
341 checksum_t checksum() const
342 { return optionalFields_().get<1>().checksum(); }
344 void enableChecksum() const { optionalFields_().init<1>(); }
345 void disableChecksum() const { optionalFields_().init<0>(); }
347 SENF_PARSER_FINALIZE(GREPacketParser);
349 checksum_t::value_type calculateChecksum() const;
352 // In the implementation (.cc) file:
354 #include <senf/Utils/IpChecksum.hh>
356 GREPacketParser::checksum_t::value_type GREPacketParser::calculateChecksum() const
358 if (!checksumEnabled())
363 cs.feed( i(), i()+4 );
364 // Skip even number of 0 bytes (the 2 bytes checksum field)
365 // cs.feed(0); cs.feed(0);
366 cs.feed( i()+6, data().end() );
373 \section howto_newpacket_type Defining the packet type
375 After we have implemented the \c GREPacketParser we now need to build the packet type. This is
376 done by providing a special policy class called the 'packet type'. This class encapsulates all
377 the information the packet library needs to know about a packet:
380 \subsection howto_newpacket_type_skeleton The packet type skeleton
382 For every type of packet, the 'packet type' class will look roughly the same. If the packet
383 utilizes a registry and is not hopelessly complex, the packet type will almost always look like
386 #include <senf/Packets.hh>
389 : public senf::PacketTypeBase,
390 public senf::PacketTypeMixin<GREPacketType, EtherTypes>
392 typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
393 typedef senf::ConcretePacket<GREPacketType> packet;
394 typedef senf::GREPacketParser parser;
396 using mixin::nextPacketRange;
397 using mixin::nextPacketType;
399 using mixin::initSize;
401 // Define members here
404 We note, that \c GREPacketType derives from two classes: senf::PacketTypeBase and
405 senf::PacketTypeMixin. senf::PacketTypeBase must be inherited by every packet type class. the
406 senf::PacketTypeMixin provides default implementations for some members which are useful for
407 most kinds of packets. If a packet type is very complex and these defaults don't work, the mixin
408 class can and should be left out. More on this (what the default members do exactly and when the
409 mixin can be used) can be found in the senf::PacketTypeMixin documentation.
411 Of the typedefs, only \a parser is mandatory. It defines the packet parser to use to interpret
412 this type of packet. \a mixin and \a packet are defined to simplify the following
413 definitions (More on \a packet and senf::ConcretePacket later).
415 The next block of statements imports all the default implementations provided by the mixin
418 \li \a nextPacketRange provides information about where the next packet lives within the GRE
420 \li \a nextPacketType provides the type of the next packet from information in the GRE packet.
421 \li \a init is called to initialize a new GRE packet. This call is forwarded to \c
422 GREPacketParser::init.
423 \li \a initSize is called to find the size of an empty (newly create) GRE packet. This is also
424 provided by GREPacketParser.
426 With these default implementations provided by the mixin, only a few additional members are
427 needed to complete the \c GREPacketType: \a nextPacketKey, \a finalize, and \a dump
430 \subsection howto_newpacket_type_registry Utilizing the packet registry
432 We want the GRE packet to utilize the senf::EtherTypes registry to find the type of packet
433 contained in the GRE payload. A registry maps an arbitrary key value to a packet type
434 represented by a packet factory instance. The details have already been taken care of by the
435 senf::PacketTypeMixin (it provides the \a nextPacketType member). However, to lookup the packet
436 in the registry, the mixin needs to know the key value. To this end, we implement \a
437 nextPacketKey(), which is very simple:
440 static key_t nextPacketKey(packet p) { return p->protocolType(); }
443 All \c GREPacketType members are static. They are passed the packet in question as an
444 argument. \a nextPacketKey() just needs to return the value of the correct packet field. And
445 since the \c parser type (as defined as a typedef) allows direct access to the packet parser
446 using the <tt>-></tt> operator, we can simply access that value.
448 The \c key_t return type is a typedef provided by the mixin class it is taken from the type of
449 registry, in this case it is senf::EtherTypes::key_t (which is defined as a 16 bit unsigned
452 With this information, the packet library can now find out the type of packet needed to parse
453 the GRE payload -- as long as the protocolType() is registered with the senf::EtherTypes
454 registry. If this is not the case, the packet library will not try to interpret the payload, it
455 will return a senf::DataPacket.
457 One special case of GRE encapsulation occurs when layer 2 frames and especially ethernet frames
458 are carried in the GRE payload. The ETHERTYPE registry normally only contains layer 3 protocols
459 (like IP or IPX) however for this special case, the value 0x6558 has been added to the ETHERTYPE
460 registry. So we need to add this value to inform the packet library to parse the payload as an
461 ethernet packet if the \a protocolType() is 0x6558. This happens in the implementation file (the
465 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
467 SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
470 This macro registers the value 0x6558 in the senf::EtherTypes registry and associates it with
471 the packet type senf::EthernetPacket. This macro declares an anonymous static variable, it
472 therefore must always be placed in the implementation file and \e never in an include file.
474 Additionally, we want the GRE packet to be parsed when present as an IP payload. Therefore we
475 additionally need to register GRE in the senf::IpTypes registry. Looking at the <a
476 href="http://www.iana.org/assignments/protocol-numbers">IP protocol numbers</a>, we find that
477 GRE has been assigned the value 47:
480 #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
482 SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
485 But wait -- what is \c GREPacket ? This question is answered a few section further down.
488 \subsection howto_newpacket_type_invariants Providing packet invariants
490 Many packets have some invariants that must hold: The payload size must be equal to some field,
491 a checksum must match and so on. When packets are newly created or changed, these invariants
492 have to be updated to be correct. This is the responsibility of the \a finalize() member. This
493 is also the place, where the \a protocolType() field is assigned.
496 static void finalize(packet p)
498 p->protocolType() << key(p.next(senf::nothrow));
499 if (p->checksumPresent())
500 p->checksum() << p->calculateChecksum();
504 \a finalize() firs sets the \a protocolType() field depending on the \e next packet. The \c
505 key() function is provided by the mixin class: It will lookup the \e type of a packet in the
506 registry and return that packets key in the registry.
508 It then updates the \a checksum() field if present (this always needs to be done last since the
509 checksum depends on the other field values).
511 Here we are using the more generic parser assignment expressed using the \c << operator. This
512 operator in the most cases works like an ordinary assignment, however it can also be used to
513 assign parsers to each other efficiently and it supports 'optional values' (as provided by <a
514 href="http://www.boost.org/libs/optional/doc/optional.html">Boost.Optional</a> and as returned
518 \subsection howto_newpacket_type_dump Writing out a complete packet: The 'dump()' member
520 For diagnostic purposes, every packet should provide a meaningful \a dump() member which writes
521 out the complete packet. This member is simple to implement and is often very helpful when
522 tracking down problems.
525 #include <boost/io/ios_state.hpp>
527 static void dump(packet p, std::ostream & os)
529 boost::io::ios_all_saver ias(os);
530 os << "General Routing Encapsulation:\n"
531 << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n"
532 << " version : " << p->version() << "\n"
533 << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0')
534 << p->protocolType() << "\n";
535 if (p->checksumPresent())
536 os << " checksum : 0x" << std::hex << std::setw(4)
537 << std::setfill('0') << p->checksum() << "\n";
541 This member is quite straight forward. We should try to adhere to the formating standard shown
542 above: The first line should be the type of packet/header being dumped followed by one line for
543 each protocol field. The colon's should be aligned at column 33 with the field name indented by
546 The \c boost::ios_all_saver is just used to ensure, that the stream formatting state is restored
547 correctly at the end of the method. An instance of this type will save the stream state when
548 constructed and will restore that state when destructed.
550 \subsection howto_newpacket_type_final Final touches
552 The \c GREPacket implementation is now almost complete. The only thing missing is the \c
553 GREPacket itself. \c GREPacket is just a typedef for a specific senf::ConcretePacket template
554 instantiation. Here the complete GREPacket definition:
557 #include <senf/Packets.hh>
560 : public senf::PacketTypeBase,
561 public senf::PacketTypeMixin<GREPacketType, EtherTypes>
563 typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
564 typedef senf::ConcretePacket<GREPacketType> packet;
565 typedef senf::GREPacketParser parser;
567 using mixin::nextPacketRange;
568 using mixin::nextPacketType;
570 using mixin::initSize;
572 static key_t nextPacketKey(packet p) { return p->protocolType(); }
574 static void finalize(packet p) {
575 p->protocolType() << key(p.next(senf::nothrow));
576 if (p->checksumPresent()) p->checksum() << p->calculateChecksum();
579 static void dump(packet p, std::ostream & os);
582 typedef GREPacketType::packet GREPacket;
584 // In the implementation (.cc) file:
586 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
587 #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
589 SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
590 SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
592 void GREPacketType::dump(packet p, std::ostream & os)
594 boost::io::ios_all_saver ias(os);
595 os << "General Routing Encapsulation:\n"
596 << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n"
597 << " version : " << p->version() << "\n"
598 << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0')
599 << p->protocolType() << "\n";
600 if (p->checksumPresent())
601 os << " checksum : 0x" << std::hex << std::setw(4)
602 << std::setfill('0') << p->checksum() << "\n";
607 \section howto_newpacket_advanced Going further
609 \subsection howto_newpacket_advanced_valid Checking the GRE packet for validity
611 We have implemented the \c GREPacket completely by now. There is however still room for
612 improvement. Reading the RFC, there are some restrictions which a packet needs to obey to be
613 considered valid. If the packet is not valid it cannot be parsed and should be dropped. There
614 are two conditions which lead to this: If one of the \a reserved0 fields first 5 bits is set or
615 if the version is not 0. We will add a \a valid() check to the parser and utilize this check in
618 So first lets update the parser. We will need to change the fields a little bit so we have
619 access to the first 5 bits of \a reserved0. We therefore replace the first three field
623 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
624 SENF_PARSER_PRIVATE_BITFIELD ( reserved0_5bits_, 5, unsigned );
625 SENF_PARSER_SKIP_BITS ( 7 );
626 SENF_PARSER_PRIVATE_BITFIELD ( version_, 3, unsigned );
629 We have added an additional private bitfield \a reserved0_5bits_() and we made the \a version_()
630 field private since we do not want the user to change the value (0 is the only valid value, any
631 other value is not supported by this parser anyways). In this special case, a read-only field
632 would do. But more generally, if there are fields which must have a fixed value, they must be
633 defined as private fields so they can be initialized by the parser to their correct value (see
634 next section on how). An additional public read-only accessor allows users of the parser to read
635 out the value (but not change it).
637 We will now add two additional simple members to the parser
640 typedef version__t version_t;
641 version_t::value_type version() const { return version_(); }
643 bool valid() const { return version() == 0 && reserved0_5bits_() == 0; }
646 I think, both are quite straight forward: \a version() will allow the user to read out the value
647 of the version field. However, since it does \e not return a parser but a numeric value, the
648 access is read-only. The \a valid() member will just check the restrictions as defined in the RFC.
650 Now to the packet type. We want to refrain from parsing the payload if the packet is
651 invalid. This is important: If the packet is not valid, we have no idea, whether the payload is
652 what we surmise it to be (if any of the \a reserved0_5bits_() are set, the packet is from an
653 older GRE RFC and the header is quite a bit longer so the payload will be incorrect).
655 So we need to change the logic which is used by the packet library to find the type of the next
656 packet. We have two ways to do this: We keep using the default \c nextPacketType()
657 implementation as provided by the senf::PacketTypeMixin and have our \a nextPacketKey()
658 implementation return a key value which is guaranteed never to be registered in the registry.
660 The more flexible possibility is implementing \c nextPacketType() ourselves. In this case, the
661 first method would suffice, but we will choose to go the second route to show how to write the
662 \c nextPacketType() member. We therefore remove the \c using declaration of \c nextPacketType()
663 and also remove the \a nextPacketKey() implementation. Instead we add the following to the
667 // disabled: using Min::nextPacketType;
669 factory_t nextPacketType(packet p) { return p->valid() ? lookup(p->protocolType()) : no_factory(); }
672 As we see, this is still quite simple. \c factory_t is provided by senf::PacketTypeBase. For our
673 purpose it is an opaque type which somehow enables the packet library to create a new packet of
674 a specified packet type. The \c factory_t has a special value, \c no_factory() which stands for
675 the absence of any concrete factory. In a boolean context this (and only this) \c factory_t
676 value tests \c false.
678 The \c lookup() member is provided by the senf::PacketTypeMixin. It looks up the key passed as
679 argument in the registry and returns the factory or \c no_factory(), if the key was not found in
682 In this case this is all. We can however return the factory for some specific type easily as in
683 the following example:
686 factory_t nextPacketType(packet p) {
688 if (p->protocolType() == 0x6558) return senf::EthernetPacket::factory();
689 else return lookup(p->protocolType());
691 else return no_factory();
695 Of course, this example is academic since senf::EthernetPacket is correctly registered in the
696 senf::EtherTypes registry but you get the picture.
699 \subsection howto_newpacket_advanced_init Non-trivial packet initialization
701 When we create a new GRE packet using the packet library, the library will initialize the packet
702 with all 0 bytes. It just happens, that this is correct for our GRE packet. Lets just for the
703 sake of experiment assume, the GRE packet would have to set \a version() to 1 not 0. In this
704 case, the default initialization would not suffice. It is however very simple to explicitly
705 initialize the packet. The initialization happens within the parser. We just add
708 SENF_PARSER_INIT() { version_() << 1u; }
711 to \c GREPacketParser. Here we see, why we have defined \a version_() as a private and not a
715 \section howto_newpacket_final The ultimate GRE packet implementation completed
717 So here we now have \c GREPacket finally complete in all it's glory. First the header file \c
721 #ifndef HH_GREPacket_
722 #define HH_GREPacket_
724 #include <senf/Packets.hh>
726 struct GREPacketParser_OptFields : public senf::PacketParserBase
728 # include SENF_FIXED_PARSER()
730 SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
731 SENF_PARSER_SKIP ( 2 );
733 SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
736 struct GREPacketParser : public senf::PacketParserBase
738 # include SENF_PARSER()
740 SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool );
741 SENF_PARSER_PRIVATE_BITFIELD ( reserved0_5bits_, 5, unsigned );
742 SENF_PARSER_SKIP_BITS ( 7 );
743 SENF_PARSER_PRIVATE_BITFIELD ( version_, 3, unsigned );
745 SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser );
747 SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
748 (senf::VoidPacketParser)
749 (GREPacketParser_OptFields) );
751 typedef version__t version_t;
752 version_t::value_type version() const { return version_(); }
754 bool valid() const { return version() == 0 && reserved0_5bits_() == 0; }
756 typedef GREPacketParser_OptFields::checksum_t checksum_t;
757 checksum_t checksum() const
758 { return optionalFields_().get<1>().checksum(); }
760 void enableChecksum() const { optionalFields_().init<1>(); }
761 void disableChecksum() const { optionalFields_().init<0>(); }
763 SENF_PARSER_FINALIZE(GREPacketParser);
765 checksum_t::value_type calculateChecksum() const;
769 : public senf::PacketTypeBase,
770 public senf::PacketTypeMixin<GREPacketType, EtherTypes>
772 typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
773 typedef senf::ConcretePacket<GREPacketType> packet;
774 typedef senf::GREPacketParser parser;
776 using mixin::nextPacketRange;
778 using mixin::initSize;
780 factory_t nextPacketType(packet p)
781 { return p->valid() ? lookup(p->protocolType()) : no_factory(); }
783 static void finalize(packet p) {
784 p->protocolType() << key(p.next(senf::nothrow));
785 if (p->checksumPresent()) p->checksum() << p->calculateChecksum();
788 static void dump(packet p, std::ostream & os);
791 typedef GREPacketType::packet GREPacket;
796 And the implementation file \c GREPacket.cc:
799 #include "GREPacket.hh"
800 #include <senf/Utils/IpChecksum.hh>
801 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
802 #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
804 SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
805 SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
807 GREPacketParser::checksum_t::value_type GREPacketParser::calculateChecksum() const
809 if (!checksumEnabled())
814 cs.feed( i(), i()+4 );
815 // Skip even number of 0 bytes (the 2 bytes checksum field)
816 // cs.feed(0); cs.feed(0);
817 cs.feed( i()+6, data().end() );
822 void GREPacketType::dump(packet p, std::ostream & os)
824 boost::io::ios_all_saver ias(os);
825 os << "General Routing Encapsulation:\n"
826 << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n"
827 << " version : " << p->version() << "\n"
828 << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0')
829 << p->protocolType() << "\n";
830 if (p->checksumPresent())
831 os << " checksum : 0x" << std::hex << std::setw(4)
832 << std::setfill('0') << p->checksum() << "\n";
837 \section howto_newpacket_using Using the newly created GRE packet type
839 The GRE packet is now fully integrated into the packet library framework. For example, we can
840 read GRE packets from a raw INet socket and forward decapsulated Ethernet frames to a packet
845 #include <senf/Packets.hh>
846 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
847 #include <senf/Socket/Protocols/INet/RawINetProtocol.hh>
848 #include <senf/Socket/Protocols/Raw/PacketSocketHandle.hh>
849 #include "GREPacket.hh"
851 int main(int, char const **)
853 senf::RawV6ClientSocketHandle isock (47u); // 47 = Read GRE packets
854 senf::PacketSocketHandle osock;
858 GREPacket gre (GREPacket::create(senf::noinit));
859 isock.read(gre.data(),0u);
860 if (gre->checksumPresent() && gre->checksum() != gre->calculateChecksum())
861 throw InvalidPacketChainException();
862 osock.write(gre.next<EthernetPacket>().data())
864 catch (senf::TruncatedPacketException & ex) {
865 std::cerr << "Malformed packet dropped\n";
867 catch (senf::InvalidPacketChainException & ex) {
868 std::cerr << "Invalid GRE packet dropped\n";
874 Or we can do the opposite: Read ethernet packets from a \c tap device and send them out GRE
879 #include <senf/Packets.hh>
880 #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
881 #include <senf/Socket/Protocols/INet/RawINetProtocol.hh>
882 #include <senf/Socket/Protocols/Raw/TunTapSocketHandle.hh>
883 #include "GREPacket.hh"
885 int main(int argc, char const ** argv)
888 std::cerr << "Usage: " << argv[0] << " <tunnel endpoint>\n";
892 senf::TapSocketHandle tap ("tap0");
893 senf::ConnectedRawV6ClientSocketHandle osock (47u, senf::INet6SocketAddress(argv[1]));
896 senf::EthernetPacket eth (senf::EthernetPacket::create(senf::noinit));
897 isock.read(eth.data(),0u);
898 GREPacket gre (senf::GREPacket::createBefore(eth));
900 osock.write(gre.data());
906 \section howto_newpacket_further Further reading
908 Lets start with references to the important API's (Use the <i>List of all members</i> link to
909 get the complete API of one of the classes and templates):
911 <table class="senf fixedcolumn">
913 <tr><td>senf::ConcretePacket</td> <td>this is the API provided by the packet handles.</td></tr>
915 <tr><td>senf::PacketData</td> <td>this API provides raw data access accessible via the handles
916 'data' member.</td></tr>
918 <tr><td>senf::PacketParserBase</td> <td>this is the generic parser API. This API is accessible
919 via the packets \c -> operator or via the sub-parsers returned by the field accessors.</td></tr>
923 When implementing new packet's, the following information will be helpful:
925 <table class="senf fixedcolumn">
927 <tr><td>senf::PacketTypeBase</td> <td>here you find a description of the members which need to
928 be implemented to provide a 'packet type'. Most of these members will normally be provided by
929 the mixin helper.</td></tr>
931 <tr><td>senf::PacketTypeMixin</td> <td>here you find all about the packet type mixin and how to
934 <tr><td>\ref packetparser</td> <td>This section describes the packet parser facility.</td></tr>
936 <tr><td>\link packetparsermacros Packet parser macros\endlink</td> <td>A complete list and
937 documentation of all the packet parser macros.</td></tr>
939 <tr><td>\ref parseint, \n \ref parsecollection</td> <td>There are several lists of available
940 reusable packet parsers. However, these lists are not complete as there are other protocol
941 specific reusable parsers (without claiming to be exhaustive: senf::INet4AddressParser,
942 senf::INet6AddressParser, senf::MACAddressParser)</td></tr>
952 // comment-column: 40
953 // c-file-style: "senf"
954 // indent-tabs-mode: nil
955 // ispell-local-dictionary: "american"
956 // compile-command: "scons -u doc"