diff --git a/gtests/net/packetdrill/Makefile.common b/gtests/net/packetdrill/Makefile.common index 1f2d45ab0593cc016a4e8787b7d259e6875256c4..89e3e19abd424bceda6e21b2a396237f7614d6f0 100644 --- a/gtests/net/packetdrill/Makefile.common +++ b/gtests/net/packetdrill/Makefile.common @@ -10,7 +10,8 @@ lexer.o: lexer.l parser.o flex -olexer.c lexer.l $(CC) -O2 -g -Wall -c lexer.c -packetdrill-lib := checksum.o code.o config.o hash.o hash_map.o ip_address.o \ +packetdrill-lib := \ + checksum.o code.o config.o hash.o hash_map.o ip_address.o ip_prefix.o \ netdev.o net_utils.o \ packet.o packet_socket_linux.o packet_socket_pcap.o \ packet_checksum.o packet_parser.o packet_to_string.o \ diff --git a/gtests/net/packetdrill/ip_address.h b/gtests/net/packetdrill/ip_address.h index 596f5f9318a8d46c8d617646f6ca3341b261b0a6..1c5b8a418f7d0f430d56f555c3a4853941bcffae 100644 --- a/gtests/net/packetdrill/ip_address.h +++ b/gtests/net/packetdrill/ip_address.h @@ -35,6 +35,7 @@ struct ip_address { union { struct in_addr v4; struct in6_addr v6; + u8 bytes[16]; } ip; /* IP address (network order) */ }; diff --git a/gtests/net/packetdrill/ip_prefix.c b/gtests/net/packetdrill/ip_prefix.c new file mode 100644 index 0000000000000000000000000000000000000000..044b94d6285051b8f775e3f667b8861f0fb613e8 --- /dev/null +++ b/gtests/net/packetdrill/ip_prefix.c @@ -0,0 +1,148 @@ +/* + * 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) + * + * Implementation for operations for IPv4 and IPv6 prefixes. + */ + +#include "ip_prefix.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "logging.h" + +struct ip_prefix ip_to_prefix(const struct ip_address *ip, int prefix_len) +{ + int max_prefix_bits = 8 * ip_address_length(ip->address_family); + struct ip_prefix prefix; + + if (prefix_len < 0 || prefix_len > max_prefix_bits) + die("invalid prefix_len: %d bits", prefix_len); + + prefix.ip = *ip; + prefix.prefix_len = prefix_len; + + return prefix; +} + +void ip_prefix_normalize(struct ip_prefix *prefix) +{ + /* Find the byte and bit offset where the prefix ends. */ + int bytes = prefix->prefix_len / 8; + int bits = prefix->prefix_len % 8; + int max_prefix_bytes = ip_address_length(prefix->ip.address_family); + + /* Zero the bits beyond the prefix in the byte where it ends. */ + if (bits != 0) { + int pos = 8 - bits; + prefix->ip.ip.bytes[bytes] &= ~((1U << pos) - 1); + ++bytes; + + } + /* Zero out the rest of the bytes in the address. */ + memset(prefix->ip.ip.bytes + bytes, 0, max_prefix_bytes - bytes); +} + +/* Parse and return a prefix length (in bits) like /16 or /64 from the + * end of a string, and die if the prefix is bigger than the given max + * length. Use the maximum length if there is no prefix in the string. + */ +static int prefix_len_parse(const char *prefix_string, int max_len) +{ + int prefix_len = 0; + const char *len_str = NULL; + + len_str = strstr(prefix_string, "/"); + if (len_str != NULL) { + /* Parse prefix len in string */ + char *end = NULL; + + ++len_str; /* advance beyond '/' */ + errno = 0; + prefix_len = strtol(len_str, &end, 10); + + if (errno != 0 || *end != '\0' || + (prefix_len < 0) || (prefix_len > max_len)) + die("bad prefix length in prefix '%s'\n", + prefix_string); + } else { + /* Default prefix length is all address bits */ + prefix_len = max_len; + } + + return prefix_len; +} + +/* Copy the address part of a "<address>/<prefix>" string. */ +static char *copy_prefix_address(const char *prefix_string) +{ + const char *slash = strstr(prefix_string, "/"); + int len = 0; + if (slash != NULL) + len = slash - prefix_string; + else + len = strlen(prefix_string); + return strndup(prefix_string, len); +} + +struct ip_prefix ipv4_prefix_parse(const char *prefix_string) +{ + char *ip_str = copy_prefix_address(prefix_string); + struct ip_address ip = ipv4_parse(ip_str); + int prefix_len = prefix_len_parse(prefix_string, + 8 * ip_address_length(AF_INET)); + + free(ip_str); + + return ip_to_prefix(&ip, prefix_len); +} + +struct ip_prefix ipv6_prefix_parse(const char *prefix_string) +{ + char *ip_str = copy_prefix_address(prefix_string); + struct ip_address ip = ipv6_parse(ip_str); + int prefix_len = prefix_len_parse(prefix_string, + 8 * ip_address_length(AF_INET6)); + + free(ip_str); + + return ip_to_prefix(&ip, prefix_len); +} + +const char *ip_prefix_to_string(struct ip_prefix *prefix, char *buffer) +{ + char ip_str[ADDR_STR_LEN]; + int bytes = 0; + + memset(ip_str, 0, sizeof(ip_str)); + ip_to_string(&prefix->ip, ip_str); + + if (strlen(ip_str) + strlen("/128") + 1 > ADDR_STR_LEN) + die("address prefix would overflow buffer!"); + + bytes = snprintf(buffer, ADDR_STR_LEN, "%s/%d", + ip_str, prefix->prefix_len); + if (bytes >= ADDR_STR_LEN) + die("address prefix overflowed buffer!"); + + return buffer; +} diff --git a/gtests/net/packetdrill/ip_prefix.h b/gtests/net/packetdrill/ip_prefix.h new file mode 100644 index 0000000000000000000000000000000000000000..0b82260d119c4db3f453bfd8ab6c54e6218ef792 --- /dev/null +++ b/gtests/net/packetdrill/ip_prefix.h @@ -0,0 +1,69 @@ +/* + * 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) + * + * Types and operations for IPv4 and IPv6 address prefixes. + */ + +#ifndef __IP_PREFIX_H__ +#define __IP_PREFIX_H__ + +#include "types.h" + +#include "ip_address.h" + +/* IPv4 or IPv6 address prefix. */ +struct ip_prefix { + struct ip_address ip; + int prefix_len; /* prefix length in bits */ +}; + +static inline void ip_prefix_reset(struct ip_prefix *prefix) +{ + memset(prefix, 0, sizeof(*prefix)); +} + +/* Parse a human-readable IPv4 prefix and return it. Print an error + * to stderr and exit if there is an error parsing the prefix. + */ +extern struct ip_prefix ipv4_prefix_parse(const char *prefix_string); + +/* Parse a human-readable IPv6 prefix and return it. Print an error + * to stderr and exit if there is an error parsing the prefix. + */ +extern struct ip_prefix ipv6_prefix_parse(const char *prefix_string); + +/* Fill in the given prefix using the first 'prefix_len' bits of the + * given IP address, zeroing out bits beyond the prefix length. + */ +extern struct ip_prefix ip_to_prefix(const struct ip_address *ip, + int prefix_len); + +/* Zero the bits beyond the prefix length. */ +void ip_prefix_normalize(struct ip_prefix *prefix); + +/* Print a human-readable representation of the given IP prefix in the + * given buffer, which must be at least ADDR_STR_LEN bytes long. + * Returns a pointer to the given buffer. + */ +extern const char *ip_prefix_to_string(struct ip_prefix *prefix, + char *buffer); + +#endif /* __IP_PREFIX_H__ */ diff --git a/gtests/net/packetdrill/types.h b/gtests/net/packetdrill/types.h index 289f6af0e85c4e6ce508acb6685c220f2458933b..50d7edf2fd08637a5b38f889f0dafdb8250ee44f 100644 --- a/gtests/net/packetdrill/types.h +++ b/gtests/net/packetdrill/types.h @@ -122,8 +122,8 @@ enum ip_ecn_t { ECN_NOCHECK, }; -/* Length of output buffer for inet_ntop. */ -#define ADDR_STR_LEN ((INET_ADDRSTRLEN + INET6_ADDRSTRLEN)+1) +/* Length of output buffer for inet_ntop, plus prefix length (e.g. "/128"). */ +#define ADDR_STR_LEN ((INET_ADDRSTRLEN + INET6_ADDRSTRLEN)+5) /* Flavors of IP versions we support. */ enum ip_version_t {