+/* Parses string 's', which must be an IP address. Stores the IP address into
+ * '*ip'. Returns true if successful, otherwise false. */
+bool
+ip_parse(const char *s, ovs_be32 *ip)
+{
+ return inet_pton(AF_INET, s, ip) == 1;
+}
+
+/* Parses string 's', which must be an IP address with an optional netmask or
+ * CIDR prefix length. Stores the IP address into '*ip', netmask into '*mask',
+ * (255.255.255.255, if 's' lacks a netmask), and number of scanned characters
+ * into '*n'.
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip,
+ ovs_be32 *mask)
+{
+ int prefix;
+
+ if (ovs_scan_len(s, n, IP_SCAN_FMT"/"IP_SCAN_FMT,
+ IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask))) {
+ /* OK. */
+ } else if (ovs_scan_len(s, n, IP_SCAN_FMT"/%d",
+ IP_SCAN_ARGS(ip), &prefix)) {
+ if (prefix <= 0 || prefix > 32) {
+ return xasprintf("%s: network prefix bits not between 0 and "
+ "32", s);
+ }
+ *mask = be32_prefix_mask(prefix);
+ } else if (ovs_scan_len(s, n, IP_SCAN_FMT, IP_SCAN_ARGS(ip))) {
+ *mask = OVS_BE32_MAX;
+ } else {
+ return xasprintf("%s: invalid IP address", s);
+ }
+ return NULL;
+}
+
+/* This function is similar to ip_parse_masked_len(), but doesn't return the
+ * number of scanned characters and expects 's' to end after the ip/(optional)
+ * mask.
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask)
+{
+ int n = 0;
+
+ char *error = ip_parse_masked_len(s, &n, ip, mask);
+ if (!error && s[n]) {
+ return xasprintf("%s: invalid IP address", s);
+ }
+ return error;
+}
+
+/* Similar to ip_parse_masked_len(), but the mask, if present, must be a CIDR
+ * mask and is returned as a prefix len in '*plen'. */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip, unsigned int *plen)
+{
+ ovs_be32 mask;
+ char *error;
+
+ error = ip_parse_masked_len(s, n, ip, &mask);
+ if (error) {
+ return error;
+ }
+
+ if (!ip_is_cidr(mask)) {
+ return xasprintf("%s: CIDR network required", s);
+ }
+ *plen = ip_count_cidr_bits(mask);
+ return NULL;
+}
+
+/* Similar to ip_parse_cidr_len(), but doesn't return the number of scanned
+ * characters and expects 's' to be NULL terminated at the end of the
+ * ip/(optional) cidr. */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen)
+{
+ int n = 0;
+
+ char *error = ip_parse_cidr_len(s, &n, ip, plen);
+ if (!error && s[n]) {
+ return xasprintf("%s: invalid IP address", s);
+ }
+ return error;
+}
+
+/* Parses string 's', which must be an IPv6 address. Stores the IPv6 address
+ * into '*ip'. Returns true if successful, otherwise false. */
+bool
+ipv6_parse(const char *s, struct in6_addr *ip)
+{
+ return inet_pton(AF_INET6, s, ip) == 1;
+}
+
+/* Parses string 's', which must be an IPv6 address with an optional netmask or
+ * CIDR prefix length. Stores the IPv6 address into '*ip' and the netmask into
+ * '*mask' (if 's' does not contain a netmask, all-one-bits is assumed), and
+ * number of scanned characters into '*n'.
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ip,
+ struct in6_addr *mask)
+{
+ char ipv6_s[IPV6_SCAN_LEN + 1];
+ int prefix;
+
+ if (ovs_scan_len(s, n, " "IPV6_SCAN_FMT, ipv6_s)
+ && ipv6_parse(ipv6_s, ip)) {
+ if (ovs_scan_len(s, n, "/%d", &prefix)) {
+ if (prefix <= 0 || prefix > 128) {
+ return xasprintf("%s: IPv6 network prefix bits not between 0 "
+ "and 128", s);
+ }
+ *mask = ipv6_create_mask(prefix);
+ } else if (ovs_scan_len(s, n, "/"IPV6_SCAN_FMT, ipv6_s)) {
+ if (!ipv6_parse(ipv6_s, mask)) {
+ return xasprintf("%s: Invalid IPv6 mask", s);
+ }
+ /* OK. */
+ } else {
+ /* OK. No mask. */
+ *mask = in6addr_exact;
+ }
+ return NULL;
+ }
+ return xasprintf("%s: invalid IPv6 address", s);
+}
+
+/* This function is similar to ipv6_parse_masked_len(), but doesn't return the
+ * number of scanned characters and expects 's' to end following the
+ * ipv6/(optional) mask. */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_masked(const char *s, struct in6_addr *ip, struct in6_addr *mask)
+{
+ int n = 0;
+
+ char *error = ipv6_parse_masked_len(s, &n, ip, mask);
+ if (!error && s[n]) {
+ return xasprintf("%s: invalid IPv6 address", s);
+ }
+ return error;
+}
+
+/* Similar to ipv6_parse_masked_len(), but the mask, if present, must be a CIDR
+ * mask and is returned as a prefix length in '*plen'. */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip,
+ unsigned int *plen)
+{
+ struct in6_addr mask;
+ char *error;
+
+ error = ipv6_parse_masked_len(s, n, ip, &mask);
+ if (error) {
+ return error;
+ }
+
+ if (!ipv6_is_cidr(&mask)) {
+ return xasprintf("%s: IPv6 CIDR network required", s);
+ }
+ *plen = ipv6_count_cidr_bits(&mask);
+ return NULL;
+}
+
+/* Similar to ipv6_parse_cidr_len(), but doesn't return the number of scanned
+ * characters and expects 's' to end after the ipv6/(optional) cidr. */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen)
+{
+ int n = 0;
+
+ char *error = ipv6_parse_cidr_len(s, &n, ip, plen);
+ if (!error && s[n]) {
+ return xasprintf("%s: invalid IPv6 address", s);
+ }
+ return error;
+}