diff mbox

[ovs-dev,2/6] packets: Add ipv6_parse_masked() function.

Message ID 1447208184-66714-2-git-send-email-jpettit@ovn.org
State Accepted
Headers show

Commit Message

Justin Pettit Nov. 11, 2015, 2:16 a.m. UTC
From: Justin Pettit <jpettit@nicira.com>

Signed-off-by: Justin Pettit <jpettit@nicira.com>
---
 lib/packets.c        |   37 +++++++++++++++++++++++++++++++++++++
 lib/packets.h        |    2 ++
 tests/test-packets.c |   23 +++++++++++++++++++++++
 3 files changed, 62 insertions(+), 0 deletions(-)

Comments

Ben Pfaff Nov. 23, 2015, 6 p.m. UTC | #1
Acked-by: Ben Pfaff <blp@ovn.org>
diff mbox

Patch

diff --git a/lib/packets.c b/lib/packets.c
index 866d782..f6fd480 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -570,6 +570,43 @@  ipv6_is_cidr(const struct in6_addr *netmask)
     return true;
 }
 
+/* Parses string 's', which must be an IPv6 address with an optional
+ * CIDR prefix length.  Stores the IP address into '*ipv6' and the CIDR
+ * prefix in '*prefix'.  (If 's' does not contain a CIDR length, all-ones
+ * is assumed.)
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_masked(const char *s, struct in6_addr *ipv6, struct in6_addr *mask)
+{
+    char ipv6_s[IPV6_SCAN_LEN + 1];
+    char mask_s[IPV6_SCAN_LEN + 1];
+    int prefix;
+    int n;
+
+    if (ovs_scan(s, IPV6_SCAN_FMT"/"IPV6_SCAN_FMT"%n", ipv6_s, mask_s, &n)
+        && inet_pton(AF_INET6, ipv6_s, ipv6) == 1
+        && inet_pton(AF_INET6, mask_s, mask) == 1
+        && !s[n]) {
+        /* OK. */
+    } else if (ovs_scan(s, IPV6_SCAN_FMT"/%d%n", ipv6_s, &prefix, &n)
+        && inet_pton(AF_INET6, ipv6_s, ipv6) == 1
+        && !s[n]) {
+        if (prefix <= 0 || prefix > 128) {
+            return xasprintf("%s: prefix bits not between 0 and 128", s);
+        }
+        *mask = ipv6_create_mask(prefix);
+    } else if (ovs_scan(s, IPV6_SCAN_FMT"%n", ipv6_s, &n)
+               && inet_pton(AF_INET6, ipv6_s, ipv6) == 1
+               && !s[n]) {
+        *mask = in6addr_exact;
+    } else {
+        return xasprintf("%s: invalid IP address", s);
+    }
+    return NULL;
+}
+
 /* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst',
  * 'eth_src' and 'eth_type' parameters.  A payload of 'size' bytes is allocated
  * in 'b' and returned.  This payload may be populated with appropriate
diff --git a/lib/packets.h b/lib/packets.h
index 6a52b32..188cf84 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -959,6 +959,8 @@  struct in6_addr ipv6_addr_bitand(const struct in6_addr *src,
 struct in6_addr ipv6_create_mask(int mask);
 int ipv6_count_cidr_bits(const struct in6_addr *netmask);
 bool ipv6_is_cidr(const struct in6_addr *netmask);
+char *ipv6_parse_masked(const char *s, struct in6_addr *ipv6,
+                        struct in6_addr *mask);
 
 void *eth_compose(struct dp_packet *, const struct eth_addr eth_dst,
                   const struct eth_addr eth_src, uint16_t eth_type,
diff --git a/tests/test-packets.c b/tests/test-packets.c
index 88b69c9..c4494cf 100644
--- a/tests/test-packets.c
+++ b/tests/test-packets.c
@@ -152,12 +152,35 @@  test_ipv6_masking(void)
 }
 
 static void
+test_ipv6_parsing(void)
+{
+    struct in6_addr o_ipv6, p_ipv6;
+    struct in6_addr mask;
+
+    inet_pton(AF_INET6, "2001:db8:0:0:0:0:2:1", &o_ipv6);
+
+    ipv6_parse_masked("2001:db8:0:0:0:0:2:1/64", &p_ipv6, &mask);
+    assert(ipv6_addr_equals(&o_ipv6, &p_ipv6));
+    assert(ipv6_count_cidr_bits(&mask) == 64);
+
+    ipv6_parse_masked("2001:db8:0:0:0:0:2:1/ffff:ffff:ffff:ffff::",
+                      &p_ipv6, &mask);
+    assert(ipv6_addr_equals(&o_ipv6, &p_ipv6));
+    assert(ipv6_count_cidr_bits(&mask) == 64);
+
+    ipv6_parse_masked("2001:db8:0:0:0:0:2:1", &p_ipv6, &mask);
+    assert(ipv6_addr_equals(&o_ipv6, &p_ipv6));
+    assert(ipv6_count_cidr_bits(&mask) == 128);
+}
+
+static void
 test_packets_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     test_ipv4_cidr();
     test_ipv6_static_masks();
     test_ipv6_cidr();
     test_ipv6_masking();
+    test_ipv6_parsing();
 }
 
 OVSTEST_REGISTER("test-packets", test_packets_main);