diff options
author | Jianfeng Tan <henry.tjf@antfin.com> | 2019-11-18 06:59:50 +0000 |
---|---|---|
committer | Jianfeng Tan <henry.tjf@antfin.com> | 2020-03-05 01:31:33 +0800 |
commit | 78c896b3b3127515478090c19447e27dc406427e (patch) | |
tree | d6d67d4683e9ca0409f9984a834547a572fb5310 /test/packetdrill/packet.h | |
parent | e4380f4866091fd92a7a57667dd938a99144f9cd (diff) |
TLDKv2dev-next-socket
Signed-off-by: Jianfeng Tan <henry.tjf@antfin.com>
Signed-off-by: Jielong Zhou <jielong.zjl@antfin.com>
Signed-off-by: Jian Zhang <wuzai.zj@antfin.com>
Signed-off-by: Chen Zhao <winters.zc@antfin.com>
Change-Id: I55c39de4c6cd30f991f35631eb507f770230f08e
Diffstat (limited to 'test/packetdrill/packet.h')
-rw-r--r-- | test/packetdrill/packet.h | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/test/packetdrill/packet.h b/test/packetdrill/packet.h new file mode 100644 index 0000000..aa41104 --- /dev/null +++ b/test/packetdrill/packet.h @@ -0,0 +1,425 @@ +/* + * Copyright 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +/* + * Author: ncardwell@google.com (Neal Cardwell) + * + * Interface and type declarations for a representation of TCP/IP packets. + * Packets are represented in their wire format. + */ + +#ifndef __PACKET_H__ +#define __PACKET_H__ + +#include "types.h" + +#include <sys/time.h> +#include "assert.h" +#include "gre.h" +#include "header.h" +#include "icmp.h" +#include "icmpv6.h" +#include "ip.h" +#include "ipv6.h" +#include "tcp.h" +#include "udp.h" +#include "unaligned.h" + +/* The data offset field is 4 bits, and specifies the length of the TCP header, + * including options, in 32-bit words. + */ +#define MAX_TCP_HEADER_BYTES (15*4) + +#define MAX_TCP_DATAGRAM_BYTES (64*1024) /* for sanity-checking */ +#define MAX_UDP_DATAGRAM_BYTES (64*1024) /* for sanity-checking */ + +/* We allow reading pretty big packets, since some interface MTUs can + * be pretty big (the Linux loopback MTU, for example, is typically + * around 16KB). + */ +static const int PACKET_READ_BYTES = 64 * 1024; + +/* Maximum number of headers. */ +#define PACKET_MAX_HEADERS 6 + +/* Maximum number of bytes of headers. */ +#define PACKET_MAX_HEADER_BYTES 256 + +/* TCP/UDP/IPv4 packet, including IPv4 header, TCP/UDP header, and data. There + * may also be a link layer header between the 'buffer' and 'ip' + * pointers, but we typically ignore that. The 'buffer_bytes' field + * gives the total space in the buffer, which may be bigger than the + * actual amount occupied by the packet data. + */ +struct packet { + u8 *buffer; /* data buffer: full contents of packet */ + u32 buffer_bytes; /* bytes of space in data buffer */ + u32 l2_header_bytes; /* bytes in outer hardware/layer-2 header */ + u32 ip_bytes; /* bytes in outermost IP hdrs/payload */ + enum direction_t direction; /* direction packet is traveling */ + + /* Metadata about all the headers in the packet, including all + * layers of encapsulation, from outer to inner, starting from + * the outermost IP header at headers[0]. + */ + struct header headers[PACKET_MAX_HEADERS]; + + /* The following pointers point into the 'buffer' area. Each + * pointer may be NULL if there is no header of that type + * present in the packet. In each case these are pointers to + * the innermost header of that kind, since that is where most + * of the interesting TCP/UDP/IP action is. + */ + + /* Layer 3 */ + struct ipv4 *ipv4; /* start of IPv4 header, if present */ + struct ipv6 *ipv6; /* start of IPv6 header, if present */ + + /* Layer 4 */ + struct tcp *tcp; /* start of TCP header, if present */ + struct udp *udp; /* start of UDP header, if present */ + struct icmpv4 *icmpv4; /* start of ICMPv4 header, if present */ + struct icmpv6 *icmpv6; /* start of ICMPv6 header, if present */ + bool echoed_header; /* icmp payload is an echoed header? + This is for TCP/UDP */ + + + s64 time_usecs; /* wall time of receive/send if non-zero */ + + u32 flags; /* various meta-flags */ +#define FLAG_WIN_NOCHECK 0x1 /* don't check TCP receive window */ +#define FLAG_OPTIONS_NOCHECK 0x2 /* don't check TCP options */ + + enum tos_chk_t tos_chk; /* how to treat the TOS byte of a packet */ + + __be32 *tcp_ts_val; /* location of TCP timestamp val, or NULL */ + __be32 *tcp_ts_ecr; /* location of TCP timestamp ecr, or NULL */ + int mss; +}; + +/* A simple list of packets. */ +struct packet_list { + struct packet *packet; /* the packet content */ + struct packet_list *next; /* link to next element, or NULL if last */ +}; + +/* Allocate a packet_list and initialize its fields to NULL. */ +extern struct packet_list *packet_list_new(void); + +/* Free an entire packet list. */ +extern void packet_list_free(struct packet_list *list); + +/* Allocate and initialize a packet. */ +extern struct packet *packet_new(u32 buffer_length); + +/* Free all the memory used by the packet. */ +extern void packet_free(struct packet *packet); + +/* Create a packet that is a copy of the contents of the given packet. */ +extern struct packet *packet_copy(struct packet *old_packet); + +/* Return the number of headers in the given packet. */ +extern int packet_header_count(const struct packet *packet); + +/* Attempt to append a new header to the given packet. Return a + * pointer to the new header metadata, or NULL if we can't add the + * header. + */ +extern struct header *packet_append_header(struct packet *packet, + enum header_t header_type, + int header_bytes); + +/* Return a newly-allocated packet that is a copy of the given inner packet + * but with the given outer packet prepended. + */ +extern struct packet *packet_encapsulate(struct packet *outer, + struct packet *inner); + +/* Aggregate a list of packets into a new packet carrying the combined + * payload and return the newly allocated packet. The head and tail parameters + * point to the first and the last packet, respectively, in the input list. + * payload_size is the payload size for the aggregated packet, equal to the + * summed payload across all the packets in the list. + * The source packets were previously checked to have compatible headers. Copy + * the headers from the last source packet, and update the length fields in all + * the headers to match the combined payload. + */ +extern struct packet *aggregate_packets(const struct packet_list *head, + const struct packet_list *tail, + int payload_size); + +/* Encapsulate a packet and free the original outer and inner packets. */ +static inline struct packet *packet_encapsulate_and_free(struct packet *outer, + struct packet *inner) +{ + struct packet *packet = packet_encapsulate(outer, inner); + packet_free(outer); + packet_free(inner); + return packet; +} + +/* Return the direction in which the given packet is traveling. */ +static inline enum direction_t packet_direction(const struct packet *packet) +{ + return packet->direction; +} + +/* Convenience accessors for peeking around in the packet... */ + +/* Return the address family corresponding to the packet protocol. */ +static inline int packet_address_family(const struct packet *packet) +{ + if (packet->ipv4 != NULL) + return AF_INET; + if (packet->ipv6 != NULL) + return AF_INET6; + return AF_UNSPEC; +} + +/* Return a pointer to the first byte of the outermost IP header. */ +static inline u8 *packet_start(const struct packet *packet) +{ + u8 *start = packet->headers[0].h.ptr; + assert(start != NULL); + return start; +} + +/* Return a pointer to the first byte of the innermost IP header. */ +static inline u8 *ip_start(struct packet *packet) +{ + if (packet->ipv4 != NULL) + return (u8 *)packet->ipv4; + if (packet->ipv6 != NULL) + return (u8 *)packet->ipv6; + assert(!"bad address family"); + return 0; +} + + +/* Return the length in bytes of the IP header for packets of the + * given address family, assuming no IP options. + */ +static inline int ip_header_min_len(int address_family) +{ + if (address_family == AF_INET) + return sizeof(struct ipv4); + else if (address_family == AF_INET6) + return sizeof(struct ipv6); + else + assert(!"bad ip_version in config"); +} + +/* Return the layer4 protocol of the packet. */ +static inline int packet_ip_protocol(const struct packet *packet) +{ + if (packet->ipv4 != NULL) + return packet->ipv4->protocol; + if (packet->ipv6 != NULL) + return packet->ipv6->next_header; + assert(!"no valid IP header"); + return 0; +} + +/* Return the length of an optionless TCP or UDP header. */ +static inline int layer4_header_len(int protocol) +{ + if (protocol == IPPROTO_TCP) + return sizeof(struct tcp); + if (protocol == IPPROTO_UDP) + return sizeof(struct udp); + assert(!"bad protocol"); + return 0; +} + +/* Return the length of the TCP header, including options. */ +static inline int packet_tcp_header_len(const struct packet *packet) +{ + assert(packet->tcp); + return packet->tcp->doff * sizeof(u32); +} + +/* Return the length of the UDP header. */ +static inline int packet_udp_header_len(const struct packet *packet) +{ + assert(packet->udp); + return sizeof(struct udp); +} + +/* Return the length of the ICMPv4 header. */ +static inline int packet_icmpv4_header_len(const struct packet *packet) +{ + assert(packet->icmpv4); + return sizeof(struct icmpv4); +} + +/* Return the length of the ICMPv6 header. */ +static inline int packet_icmpv6_header_len(const struct packet *packet) +{ + assert(packet->icmpv6); + return sizeof(struct icmpv6); +} + +/* Return the length of the TCP options. */ +static inline int packet_tcp_options_len(const struct packet *packet) +{ + assert(packet->tcp); + return packet_tcp_header_len(packet) - sizeof(*(packet->tcp)); +} + +/* Return a pointer to the TCP options. */ +static inline u8 *packet_tcp_options(struct packet *packet) +{ + assert(packet->tcp); + return (u8 *) (packet->tcp + 1); +} + +static inline u32 packet_tcp_ts_val(const struct packet *packet) +{ + return get_unaligned_be32(packet->tcp_ts_val); +} + +static inline u32 packet_tcp_ts_ecr(const struct packet *packet) +{ + return get_unaligned_be32(packet->tcp_ts_ecr); +} + +static inline void packet_set_tcp_ts_val(struct packet *packet, u32 ts_val) +{ + put_unaligned_be32(ts_val, packet->tcp_ts_val); +} + +static inline void packet_set_tcp_ts_ecr(struct packet *packet, u32 ts_ecr) +{ + put_unaligned_be32(ts_ecr, packet->tcp_ts_ecr); +} + +/* Return a pointer to the TCP/UDP data payload. */ +static inline u8 *packet_payload(const struct packet *packet) +{ + if (packet->tcp) + return ((u8 *) packet->tcp) + packet_tcp_header_len(packet); + if (packet->udp) + return ((u8 *) packet->udp) + packet_udp_header_len(packet); + if (packet->icmpv4) + return ((u8 *) packet->icmpv4) + packet_icmpv4_header_len(packet); + if (packet->icmpv6) + return ((u8 *) packet->icmpv6) + packet_icmpv6_header_len(packet); + + assert(!"no valid payload; not TCP or UDP or ICMP!?"); + return NULL; +} + +/* Return a pointer to the byte beyond the end of the packet. */ +static inline u8 *packet_end(const struct packet *packet) +{ + return packet_start(packet) + packet->ip_bytes; +} + +/* Return the length of the TCP/UDP payload. */ +static inline int packet_payload_len(const struct packet *packet) +{ + return packet_end(packet) - packet_payload(packet); +} + +/* Return the location of the IP header echoed by an ICMP message. */ +static inline u8 *packet_echoed_ip_header(struct packet *packet) +{ + if (packet->icmpv4 != NULL) + return (u8 *)(packet->icmpv4 + 1); + if (packet->icmpv6 != NULL) + return (u8 *)(packet->icmpv6 + 1); + assert(!"no valid icmp header"); + return NULL; +} + +/* Return the location of the IPv4 header echoed by an ICMP message, or NULL. */ +static inline struct ipv4 *packet_echoed_ipv4_header(struct packet *packet) +{ + return (struct ipv4 *)((packet->icmpv4 != NULL) ? + (packet->icmpv4 + 1) : NULL); +} + +/* Return the location of the IPv6 header echoed by an ICMP message, or NULL. */ +static inline struct ipv6 *packet_echoed_ipv6_header(struct packet *packet) +{ + return (struct ipv6 *)((packet->icmpv6 != NULL) ? + (packet->icmpv6 + 1) : NULL); +} + +/* Return the length in bytes of the IP header echoed by an ICMP message. + * For now we do not generate any IP options for echoed IP headers. + */ +static inline int packet_echoed_ip_header_len(struct packet *packet) +{ + if (packet->icmpv4 != NULL) + return sizeof(struct ipv4); + if (packet->icmpv6 != NULL) + return sizeof(struct ipv6); + assert(!"no valid icmp header"); + return 0; +} + +/* Return the layer4 protocol of the packet echoed inside an ICMP packet. */ +static inline int packet_echoed_ip_protocol(struct packet *packet) +{ + if (packet->icmpv4 != NULL) + return packet_echoed_ipv4_header(packet)->protocol; + if (packet->icmpv6 != NULL) + return packet_echoed_ipv6_header(packet)->next_header; + assert(!"no valid icmp header"); + return 0; +} + +/* Return the location of the TCP or UDP header echoed by an ICMP message. */ +static inline u8 *packet_echoed_layer4_header(struct packet *packet) +{ + u8 *echoed_ip = packet_echoed_ip_header(packet); + int ip_header_len = packet_echoed_ip_header_len(packet); + return echoed_ip + ip_header_len; +} + +/* Return the location of the TCP header echoed by an ICMP message. */ +static inline struct tcp *packet_echoed_tcp_header(struct packet *packet) +{ + if (packet_echoed_ip_protocol(packet) == IPPROTO_TCP) + return (struct tcp *)(packet_echoed_layer4_header(packet)); + return NULL; +} + +/* Return the location of the UDP header echoed by an ICMP message. */ +static inline struct udp *packet_echoed_udp_header(struct packet *packet) +{ + if (packet_echoed_ip_protocol(packet) == IPPROTO_UDP) + return (struct udp *)(packet_echoed_layer4_header(packet)); + return NULL; +} + +/* Return the location of the TCP sequence number echoed by an ICMP message. */ +static inline u32 *packet_echoed_tcp_seq(struct packet *packet) +{ + struct tcp *echoed_tcp = packet_echoed_tcp_header(packet); + assert(echoed_tcp); + u32 *seq = &(echoed_tcp->seq); + /* Check that the seq field is actually in the space we + * reserved for the echoed prefix of the TCP header. + */ + assert((char *) (seq + 1) <= (char *) echoed_tcp + ICMP_ECHO_BYTES); + return seq; +} + +#endif /* __PACKET_H__ */ |