PktGen

PktGen is a SysUnit API for generating and validating packets. PktGen is based around packet templates -- immutable structures that describe every field in a header. Templates are arbitrarily composable, subject to certain restrictions (e.g. an IPv4 header may only be encapsulated in a header that has an Ethertype field).

New templates may be defined by applying mutators to an existing template. This generates a template with all of the same header field values as the original template, but with the fields affected by the mutators changed to the new values specified by the mutator.

Packets (referenced via an mbuf chain) can be generated from a packet template via the Generate() method. As templates are immutable, it is safe to call this multiple times. Each call will generate a new mbuf with identical contents. The mbuf returned from Generate() is wrapped in a std::unique_ptr, typedefed as PktGen::MbufUniquePtr. The unique_ptr will automatically free the mbuf when the object goes out of scope. If this behaviour is not wanted, GenerateRawMbuf() will return a struct mbuf * that must be freed manually by calling m_freem().

A PacketMatcher can be used for validating that an mbuf's contents exactly matches the fields specified in a template.

Examples

   1 using namespace PktGen;
   2 
   3 // Create a packet template that describes a packet with a single IPv4 header
   4 // with a source IP of 192.168.1.1 and a dest IP of 192.168.1.2.  All other
   5 // fields in the template have their default values.
   6 auto pktTemplate = PacketTemplate(
   7      Ipv4Header()
   8          .With(
   9             src("192.168.1.1"),
  10             dst("192.168.1.2")
  11          )
  12     );
  13 
  14 
  15 // Create a packet template that describes a packet with an Ethernet header,
  16 // an IPv6 header, a TCP header and a payload.  The Ethertype, IP Protocol,
  17 // IP length and checksum (IP and TCP) fields will be automatically set 
  18 // appropriately.  Other fields that are not explicitly specified get default
  19 // values.
  20 auto pktTemplate2 = PacketTemplate(
  21     EthernetHeader()
  22         .With(
  23              src("02:01:02:03:04:05"),
  24              dst("56:ed:59:33:73:67")
  25         ),
  26      Ipv6Header()
  27          .With(
  28              src("4898:5298::0001"),
  29              dst("2659::2659:0864"),
  30          ),
  31      TcpHeader()
  32          .With(
  33              src(2985),
  34              dst(80),
  35              seq(155658),
  36              ack(229289)
  37          ),
  38      PacketPayload()
  39          .With(
  40               payload("samplePayload")
  41          )
  42       );
  43 
  44 // Define a packet template that is the next packet in the TCP stream after
  45 // pktTemplate2 (i.e. th_seq has been incremented).  This template will have
  46 // the value "data" as its payload (4 bytes -- the null terminator is excluded)
  47 // and the th_ack field has been incremented by 1448 bytes from pktTemplate2.
  48 auto pktTemplate3 = pktTemplate2.Next()
  49      .WithHeader(Layer::L4).Fields(incrAck(+1448))
  50      .WithHeader(Layer::PAYLOAD).Fields(payload("data"));

Header Templates

Note: Any mutators that accept integer parameters accept the integer in host byte order (not network byte order).

EthernetHeader

auto PktGen::EthernetHeader(); 

Layer: PktGen::Layer::L2

Supported Mutators

Mutator

Meaning

Default

Value Type

PktGen::dst()

Specify the destination MAC.

00:00:00:00:00:00

Colon-separated MAC address.

PktGen::ethertype()

Specify the Ethertype value

Based on encapsulated header type

integer

PktGen::mtu()

Specify the maximum frame size

ULONG_MAX

integer

PktGen::mbufVlan()

Specify the value of the mbuf ether_vtag field

0

integer

PktGen::src()

Specify the source MAC.

00:00:00:00:00:00

Colon-separated MAC address.

Ipv4Header

 auto PktGen::Ipv4Header(); 

Layer: PktGen::Layer::L3

This header can only be encapsulated in headers that support the ethertype mutator.

Supported Mutators

Mutator

Meaning

Default

Value Type

PktGen::checksum()

Specify the IP checksum (ip_sum) field value

Checksum is calculated

integer

PktGen::checksumPassed()

Specify whether the mbuf CSUM_L3_VALID flag should be set

false

bool

PktGen::checksumVerified()

Specify whether the mbuf CSUM_L3_CALC flag should be set

false

bool

PktGen::dst()

Specify the destination IP

0.0.0.0

String (IP address in dotted decimal notation)

PktGen::fragOffset()

Specify the IP fragment offset field value

0

integer

PktGen::headerLength()

Specify the ip_hl field value

5

integer

PktGen::id()

Specify the ip_id field value

0

integer

PktGen::incrId(x)

Increase the ip_id field value by x

n/a

integer

PktGen::ipVersion()

Specify the ip_v field value

4

integer

PktGen::mtu()

Specify the MTU

ULONG_MAX

integer

PktGen::proto()

Specify the ip_p field value

Based on encapsulated header type

integer

PktGen::src()

Specify the source IP

0.0.0.0

String (IP address in dotted decimal notation)

PktGen::tos()

Specify the type-of-service (ip_tos) field value

0

integer

PktGen::ttl()

Specify the time-to-live (ip_ttl) field value

255

integer

Ipv6Header

 auto PktGen::Ipv6Header(); 

Layer: PktGen::Layer::L3

This header can only be encapsulated in headers that support the ethertype mutator.

Supported Mutators

Mutator

Meaning

Default

Value Type

PktGen::dst()

Specify the destination IP

::

String (IPv6 address in RFC 4291 format)

PktGen::ipVersion()

Specify the ip_v field value

6

integer

PktGen::hopLimit()

Specify the ip_hlim field value

255

integer

PktGen::mtu()

Specify the MTU

ULONG_MAX

integer

PktGen::proto()

Specify the ip6_nxt field value

Based on encapsulated header type

integer

PktGen::src()

Specify the source IP

::

String (IPv6 address in RFC 4291 format)

PktGen::ttl()

Alias for hopLimit()

n/a

integer

PacketPayload

 auto PktGen::PacketPayload(); 

Layer: PktGen::Layer::PAYLOAD

No header type (including another PacketPayload) can be encapsulated within a PacketPayload.

Supported Mutators

Mutator

Meaning

Default

PktGen::payload()

Specify an zero-length payload

Yes

PktGen::payload(const std::vector<uint8_t> &)

Specify the contents of the payload directly

n/a

PktGen::payload(uint8_t byte, size_t count = 1)

Specify a payload that consists of count repetitions of byte

n/a

PktGen::payload(const std::string & str, size_t count)

Specify a payload of length count. The string value is repeated until count bytes are filled

n/a

PktGen::payload(const char *)

Specify a payload containing the string. The null terminator is not included

n/a

PktGen::appendPayload(const std::vector<uint8_t> &)

Append the series of bytes to the current payload

n/a

PktGen::appendPayload(uint8_t byte, size_t count = 1)

Append count repetitions of byte to the payload

n/a

PktGen::appendPayload(const std::string & str, size_t count)

Append a payload of length count. The string value is repeated until count bytes are filled

n/a

PktGen::appendPayload(const char *)

Append the string to the payload. The null terminator is not included

n/a

TcpHeader

 auto PktGen::TcpHeader(); 

Layer: PktGen::Layer::L4

This header type can only be encapsulated in headers that support the proto() mutator.

Supported Mutators

Mutator

Meaning

Default

Value Type

PktGen::ack()

Specify the TCP ack (th_ack) field value

0

integer

PktGen::checksum()

Specify the TCP checksum (th_sum) field value

Checksum is calculated

integer

PktGen::checksumPassed()

Specify whether the mbuf CSUM_L4_VALID flag should be set

false

bool

PktGen::checksumVerified()

Specify whether the mbuf CSUM_L4_CALC flag should be set

false

bool

PktGen::dst()

Specify the destination port

0

integer

PktGen::flags()

Specify the TCP flags (th_flags) field value

TH_ACK

integer

PktGen::incrAck(x)

Increase the th_ack field by x

n/a

integer

PktGen::incrSeq(x)

Increase the th_seq field by x

n/a

integer

PktGen::incrWindow(x)

Increase the th_win field by x

n/a

integer

PktGen::seq()

Specify the TCP sequence number (th_seq) field value

0

integer

PktGen::src()

Specify the source port

0

integer

PktGen::window()

Specify the TCP window (th_win) field value

0

integer

PktGen::urp()

Set the th_urp field value

0

integer

Packet Template APIs

PacketTemplate

template<typename... Headers>
auto PktGen::PacketTemplate(Headers... auto);

Encapsulate one or more packet templates in each other. The first template passed to PacketTemplate() will be the outermost header, the second will be directly encapsulated in the outermost, so on, until the innermost header is specified as the last argument.

PacketMatcher

template <typename PacketTemplate>
auto PktGen::PacketMatcher(const PacketTemplate & packetTemplate);

Return a Google Mock matcher that matches a struct mbuf * against the specified template. All fields specified in every header in the template must exactly match against the headers in the mbuf's payload or the match will fail. The mbuf's length must also match the length of the specified payload.

Packet Template Methods

Each packet template supports the following methods:

Generate()

 PktGen::MbufUniquePtr Generate() const; 

Allocate an mbuf, and fill its payload with the headers that are described by *this. This method returns a std::unique_ptr smart point that will automatically free the mbuf when the smart pointer goes out of scope.

Because packet templates are immutable, this method may be safely called any number of times. It will produce an identical packet (with a unique address) every time.

GenerateRawMbuf()

 struct mbuf * GenerateRawMbuf() const; 

This is a convenience method that returns an unmanaged mbuf pointer. It is equivalent to calling Generate().release(). The returned mbuf must be freed via a call to m_freem(). A test case will fail if any mbufs are leaked.

This method is more convenient to use in the case where the mbuf pointer will be immediately passed to a code unit that will consume it (and call m_freem() on it once it is done with the mbuf).

Next()

 auto Next() const; 

Return a new packet template that describes the packet that is next in the packet stream. In the case of a TCP template, the TCP sequence number will be incremented to reflect the size of the payload of the packet described by *this. In the case of a UDP template, the IP fragment offset will increase if *this described a fragmented packet.

If no MTU was configured on the template or the length of the headers plus the payload was less than the MTU, then the new template will describe a packet with a 0-length payload. Otherwise, the payload will reflect the next part of the packet stream.

Retransmit()

 auto Retransmit() const; 

Return a new packet template that describes a packet that is a TCP retransmission of the packet described by *this. For the most part, a retransmission will be identical to *this, but in the case of IPv4 the ip_id field will have incremented.

With()

template <typename... Mutators>
auto With(Mutators... mutators) const;

Returns a new packet template. The new packet template is a copy of *this, but with the given mutators applied to modify their respective fields. The mutators are applied to the innermost header. A compile error will result if a mutator does not apply to the innermost header type.

WithHeader().Fields()

auto WithHeader(Layer layer).Fields(Mutators... mutators) const;

Returns a new packet template. The new template is a copy of *this, but with the given mutators applied to modify their respective fields in the header at the given layer. Supported values for layer are:

SysUnit/APIs/PktGen (last edited 2020-10-18T23:43:14+0000 by SashaVigole)