From: Justin Pettit <jpet...@nicira.com> Signed-off-by: Justin Pettit <jpet...@nicira.com> --- lib/packets.c | 37 +++++++++++++++++++++++++++++++++++++ lib/packets.h | 2 ++ tests/test-packets.c | 23 +++++++++++++++++++++++ 3 files changed, 62 insertions(+), 0 deletions(-)
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); -- 1.7.5.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev