aboutsummaryrefslogtreecommitdiffstats
path: root/test/packetdrill/ip_prefix.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/packetdrill/ip_prefix.c')
-rw-r--r--test/packetdrill/ip_prefix.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/test/packetdrill/ip_prefix.c b/test/packetdrill/ip_prefix.c
new file mode 100644
index 0000000..044b94d
--- /dev/null
+++ b/test/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;
+}