diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index 0932db416d5d97e54a217c49a87ad67c521fa782..212eff49ad16eb656ec1de9ac07f43f5fce7eca5 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -31,8 +31,10 @@ #include <sys/socket.h> #include <unistd.h> #include "checksum.h" +#include "gre.h" #include "logging.h" #include "netdev.h" +#include "packet.h" #include "packet_checksum.h" #include "packet_to_string.h" #include "run.h" @@ -685,32 +687,33 @@ static int tcp_options_allowance(const struct packet *actual_packet, } /* Verify that required actual IPv4 header fields are as the script expected. */ -static int verify_outbound_live_ipv4( +static int verify_ipv4( const struct packet *actual_packet, - const struct packet *script_packet, char **error) + const struct packet *script_packet, + int layer, char **error) { - if (actual_packet->ipv4 == NULL) - return STATUS_OK; + const struct ipv4 *actual_ipv4 = actual_packet->headers[layer].h.ipv4; + const struct ipv4 *script_ipv4 = script_packet->headers[layer].h.ipv4; if (check_field("ipv4_version", - script_packet->ipv4->version, - actual_packet->ipv4->version, error) || + script_ipv4->version, + actual_ipv4->version, error) || check_field("ipv4_protocol", - script_packet->ipv4->protocol, - actual_packet->ipv4->protocol, error) || + script_ipv4->protocol, + actual_ipv4->protocol, error) || check_field("ipv4_header_length", - script_packet->ipv4->ihl, - actual_packet->ipv4->ihl, error) || + script_ipv4->ihl, + actual_ipv4->ihl, error) || check_field("ipv4_total_length", - (ntohs(script_packet->ipv4->tot_len) + + (ntohs(script_ipv4->tot_len) + tcp_options_allowance(actual_packet, script_packet)), - ntohs(actual_packet->ipv4->tot_len), error)) + ntohs(actual_ipv4->tot_len), error)) return STATUS_ERR; if (verify_outbound_live_ecn(script_packet->ecn, - ipv4_ecn_bits(actual_packet->ipv4), - ipv4_ecn_bits(script_packet->ipv4), + ipv4_ecn_bits(actual_ipv4), + ipv4_ecn_bits(script_ipv4), error)) return STATUS_ERR; @@ -718,29 +721,30 @@ static int verify_outbound_live_ipv4( } /* Verify that required actual IPv6 header fields are as the script expected. */ -static int verify_outbound_live_ipv6( +static int verify_ipv6( const struct packet *actual_packet, - const struct packet *script_packet, char **error) + const struct packet *script_packet, + int layer, char **error) { - if (actual_packet->ipv6 == NULL) - return STATUS_OK; + const struct ipv6 *actual_ipv6 = actual_packet->headers[layer].h.ipv6; + const struct ipv6 *script_ipv6 = script_packet->headers[layer].h.ipv6; if (check_field("ipv6_version", - script_packet->ipv6->version, - actual_packet->ipv6->version, error) || + script_ipv6->version, + actual_ipv6->version, error) || check_field("ipv6_payload_len", - (ntohs(script_packet->ipv6->payload_len) + + (ntohs(script_ipv6->payload_len) + tcp_options_allowance(actual_packet, script_packet)), - ntohs(actual_packet->ipv6->payload_len), error) || + ntohs(actual_ipv6->payload_len), error) || check_field("ipv6_next_header", - script_packet->ipv6->next_header, - actual_packet->ipv6->next_header, error)) + script_ipv6->next_header, + actual_ipv6->next_header, error)) return STATUS_ERR; if (verify_outbound_live_ecn(script_packet->ecn, - ipv6_ecn_bits(actual_packet->ipv6), - ipv6_ecn_bits(script_packet->ipv6), + ipv6_ecn_bits(actual_ipv6), + ipv6_ecn_bits(script_ipv6), error)) return STATUS_ERR; @@ -748,100 +752,164 @@ static int verify_outbound_live_ipv6( } /* Verify that required actual TCP header fields are as the script expected. */ -static int verify_outbound_live_tcp( +static int verify_tcp( const struct packet *actual_packet, - const struct packet *script_packet, char **error) + const struct packet *script_packet, + int layer, char **error) { - assert(actual_packet->tcp != NULL); + const struct tcp *actual_tcp = actual_packet->headers[layer].h.tcp; + const struct tcp *script_tcp = script_packet->headers[layer].h.tcp; if (check_field("tcp_data_offset", - (script_packet->tcp->doff + + (script_tcp->doff + tcp_options_allowance(actual_packet, script_packet)/sizeof(u32)), - actual_packet->tcp->doff, error) || + actual_tcp->doff, error) || check_field("tcp_fin", - script_packet->tcp->fin, - actual_packet->tcp->fin, error) || + script_tcp->fin, + actual_tcp->fin, error) || check_field("tcp_syn", - script_packet->tcp->syn, - actual_packet->tcp->syn, error) || + script_tcp->syn, + actual_tcp->syn, error) || check_field("tcp_rst", - script_packet->tcp->rst, - actual_packet->tcp->rst, error) || + script_tcp->rst, + actual_tcp->rst, error) || check_field("tcp_psh", - script_packet->tcp->psh, - actual_packet->tcp->psh, error) || + script_tcp->psh, + actual_tcp->psh, error) || check_field("tcp_ack", - script_packet->tcp->ack, - actual_packet->tcp->ack, error) || + script_tcp->ack, + actual_tcp->ack, error) || check_field("tcp_urg", - script_packet->tcp->urg, - actual_packet->tcp->urg, error) || + script_tcp->urg, + actual_tcp->urg, error) || check_field("tcp_ece", - script_packet->tcp->ece, - actual_packet->tcp->ece, error) || + script_tcp->ece, + actual_tcp->ece, error) || check_field("tcp_cwr", - script_packet->tcp->cwr, - actual_packet->tcp->cwr, error) || + script_tcp->cwr, + actual_tcp->cwr, error) || check_field("tcp_reserved_bits", - script_packet->tcp->res1, - actual_packet->tcp->res1, error) || + script_tcp->res1, + actual_tcp->res1, error) || check_field("tcp_seq", - ntohl(script_packet->tcp->seq), - ntohl(actual_packet->tcp->seq), error) || + ntohl(script_tcp->seq), + ntohl(actual_tcp->seq), error) || check_field("tcp_ack_seq", - ntohl(script_packet->tcp->ack_seq), - ntohl(actual_packet->tcp->ack_seq), error) || + ntohl(script_tcp->ack_seq), + ntohl(actual_tcp->ack_seq), error) || (script_packet->flags & FLAG_WIN_NOCHECK ? STATUS_OK : check_field("tcp_window", - ntohs(script_packet->tcp->window), - ntohs(actual_packet->tcp->window), error)) || + ntohs(script_tcp->window), + ntohs(actual_tcp->window), error)) || check_field("tcp_urg_ptr", - ntohs(script_packet->tcp->urg_ptr), - ntohs(actual_packet->tcp->urg_ptr), error)) + ntohs(script_tcp->urg_ptr), + ntohs(actual_tcp->urg_ptr), error)) return STATUS_ERR; return STATUS_OK; } /* Verify that required actual UDP header fields are as the script expected. */ -static int verify_outbound_live_udp( +static int verify_udp( const struct packet *actual_packet, - const struct packet *script_packet, char **error) + const struct packet *script_packet, + int layer, char **error) { - assert(actual_packet->udp != NULL); + const struct udp *actual_udp = actual_packet->headers[layer].h.udp; + const struct udp *script_udp = script_packet->headers[layer].h.udp; if (check_field("udp_len", - script_packet->udp->len, - actual_packet->udp->len, error)) + script_udp->len, + actual_udp->len, error)) + return STATUS_ERR; + return STATUS_OK; +} + +/* Verify that required actual GRE header fields are as the script expected. */ +static int verify_gre( + const struct packet *actual_packet, + const struct packet *script_packet, + int layer, char **error) +{ + const struct gre *actual_gre = actual_packet->headers[layer].h.gre; + const struct gre *script_gre = script_packet->headers[layer].h.gre; + + /* TODO(ncardwell) check all fields of GRE header */ + if (check_field("gre_len", + gre_len(script_gre), + gre_len(actual_gre), error)) return STATUS_ERR; return STATUS_OK; } +typedef int (*verifier_func)( + const struct packet *actual_packet, + const struct packet *script_packet, + int layer, char **error); + +/* Verify that required actual header fields are as the script expected. */ +static int verify_header( + const struct packet *actual_packet, + const struct packet *script_packet, + int layer, char **error) +{ + verifier_func verifiers[HEADER_NUM_TYPES] = { + [HEADER_IPV4] = verify_ipv4, + [HEADER_IPV6] = verify_ipv6, + [HEADER_GRE] = verify_gre, + [HEADER_TCP] = verify_tcp, + [HEADER_UDP] = verify_udp, + }; + verifier_func verifier = NULL; + const struct header *actual_header = &actual_packet->headers[layer]; + const struct header *script_header = &script_packet->headers[layer]; + enum header_t type = script_header->type; + + if (script_header->type != actual_header->type) { + asprintf(error, "live packet header layer %d: " + "expected: %s header vs actual: %s header", + layer, + header_type_info(script_header->type)->name, + header_type_info(actual_header->type)->name); + return STATUS_ERR; + } + + assert(type > HEADER_NONE); + assert(type < HEADER_NUM_TYPES); + verifier = verifiers[type]; + assert(verifier != NULL); + return verifier(actual_packet, script_packet, layer, error); +} + /* Verify that required actual header fields are as the script expected. */ static int verify_outbound_live_headers( const struct packet *actual_packet, const struct packet *script_packet, char **error) { + const int actual_headers = packet_header_count(actual_packet); + const int script_headers = packet_header_count(script_packet); + int i; + assert((actual_packet->ipv4 != NULL) || (actual_packet->ipv6 != NULL)); assert((actual_packet->tcp != NULL) || (actual_packet->udp != NULL)); - if (verify_outbound_live_ipv4(actual_packet, script_packet, error) || - verify_outbound_live_ipv6(actual_packet, script_packet, error)) + if (actual_headers != script_headers) { + asprintf(error, "live packet header layers: " + "expected: %d headers vs actual: %d headers", + script_headers, actual_headers); return STATUS_ERR; + } - if (actual_packet->tcp != NULL) { - if (verify_outbound_live_tcp(actual_packet, script_packet, - error)) - return STATUS_ERR; - } else if (actual_packet->udp != NULL) { - if (verify_outbound_live_udp(actual_packet, script_packet, - error)) + /* Compare actual vs script headers, layer by layer. */ + for (i = 0; i < ARRAY_SIZE(script_packet->headers); ++i) { + if (script_packet->headers[i].type == HEADER_NONE) + break; + + if (verify_header(actual_packet, script_packet, i, error)) return STATUS_ERR; - } else { - asprintf(error, "illegal protocol in outbound packet"); - return STATUS_ERR; } + return STATUS_OK; }