The existing functions for working with sockaddr_storage that contain an IPv4 or IPv6 address are useful. This commit adds more functions for working with them, as well as a parallel set of functions for struct sockaddr.
This also adds an initial user for some of the new sockaddr functions in netdev.c. Signed-off-by: Ben Pfaff <b...@ovn.org> --- lib/netdev.c | 31 ++++-------- lib/socket-util.c | 138 +++++++++++++++++++++++++++++++++++++++--------------- lib/socket-util.h | 12 +++++ 3 files changed, 120 insertions(+), 61 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index b303a7dc558d..00192f0b00da 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -50,6 +50,7 @@ #include "seq.h" #include "openvswitch/shash.h" #include "smap.h" +#include "socket-util.h" #include "sset.h" #include "svec.h" #include "openvswitch/vlog.h" @@ -2034,29 +2035,13 @@ netdev_get_addrs(const char dev[], struct in6_addr **paddr, addr_array = xzalloc(sizeof *addr_array * cnt); mask_array = xzalloc(sizeof *mask_array * cnt); for (ifa = if_addr_list; ifa; ifa = ifa->ifa_next) { - int family; - - if (!ifa->ifa_name || !ifa->ifa_addr || !ifa->ifa_netmask - || strncmp(ifa->ifa_name, dev, IFNAMSIZ)) { - continue; - } - - family = ifa->ifa_addr->sa_family; - if (family == AF_INET) { - const struct sockaddr_in *sin; - - sin = ALIGNED_CAST(const struct sockaddr_in *, ifa->ifa_addr); - in6_addr_set_mapped_ipv4(&addr_array[i], sin->sin_addr.s_addr); - sin = ALIGNED_CAST(const struct sockaddr_in *, ifa->ifa_netmask); - in6_addr_set_mapped_ipv4(&mask_array[i], sin->sin_addr.s_addr); - i++; - } else if (family == AF_INET6) { - const struct sockaddr_in6 *sin6; - - sin6 = ALIGNED_CAST(const struct sockaddr_in6 *, ifa->ifa_addr); - memcpy(&addr_array[i], &sin6->sin6_addr, sizeof *addr_array); - sin6 = ALIGNED_CAST(const struct sockaddr_in6 *, ifa->ifa_netmask); - memcpy(&mask_array[i], &sin6->sin6_addr, sizeof *mask_array); + if (ifa->ifa_name + && ifa->ifa_addr + && ifa->ifa_netmask + && !strncmp(ifa->ifa_name, dev, IFNAMSIZ) + && sa_is_ip(ifa->ifa_addr)) { + addr_array[i] = sa_get_address(ifa->ifa_addr); + mask_array[i] = sa_get_address(ifa->ifa_netmask); i++; } } diff --git a/lib/socket-util.c b/lib/socket-util.c index 0964a015e3f9..12d16f582d52 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -53,6 +53,9 @@ VLOG_DEFINE_THIS_MODULE(socket_util); static int getsockopt_int(int fd, int level, int option, const char *optname, int *valuep); +static struct sockaddr_in *sin_cast(const struct sockaddr *); +static struct sockaddr_in6 *sin6_cast(const struct sockaddr *); +static const struct sockaddr *sa_cast(const struct sockaddr_storage *); /* Sets 'fd' to non-blocking mode. Returns 0 if successful, otherwise a * positive errno value. */ @@ -422,7 +425,7 @@ parse_sockaddr_components(struct sockaddr_storage *ss, const char *port_s, uint16_t default_port, const char *s) { - struct sockaddr_in *sin = ALIGNED_CAST(struct sockaddr_in *, ss); + struct sockaddr_in *sin = sin_cast(sa_cast(ss)); int port; if (port_s && port_s[0]) { @@ -436,9 +439,7 @@ parse_sockaddr_components(struct sockaddr_storage *ss, memset(ss, 0, sizeof *ss); if (host_s && strchr(host_s, ':')) { - struct sockaddr_in6 *sin6 - = ALIGNED_CAST(struct sockaddr_in6 *, ss); - + struct sockaddr_in6 *sin6 = sin6_cast(sa_cast(ss)); char *addr = strsep(&host_s, "%"); sin6->sin6_family = AF_INET6; @@ -1017,25 +1018,47 @@ describe_fd(int fd) #endif /* _WIN32 */ return ds_steal_cstr(&string); } - -/* sockaddr_storage helpers. */ +/* sockaddr helpers. */ + +static struct sockaddr_in * +sin_cast(const struct sockaddr *sa) +{ + return ALIGNED_CAST(struct sockaddr_in *, sa); +} + +static struct sockaddr_in6 * +sin6_cast(const struct sockaddr *sa) +{ + return ALIGNED_CAST(struct sockaddr_in6 *, sa); +} + +/* Returns true if 'sa' represents an IPv4 or IPv6 address, false otherwise. */ +bool +sa_is_ip(const struct sockaddr *sa) +{ + return sa->sa_family == AF_INET || sa->sa_family == AF_INET6; +} + +/* Returns the IPv4 or IPv6 address in 'sa'. Returns IPv4 addresses as + * v6-mapped. */ +struct in6_addr +sa_get_address(const struct sockaddr *sa) +{ + ovs_assert(sa_is_ip(sa)); + return (sa->sa_family == AF_INET + ? in6_addr_mapped_ipv4(sin_cast(sa)->sin_addr.s_addr) + : sin6_cast(sa)->sin6_addr); +} -/* Returns the IPv4 or IPv6 port in 'ss'. */ +/* Returns the IPv4 or IPv6 port in 'sa'. */ uint16_t -ss_get_port(const struct sockaddr_storage *ss) +sa_get_port(const struct sockaddr *sa) { - if (ss->ss_family == AF_INET) { - const struct sockaddr_in *sin - = ALIGNED_CAST(const struct sockaddr_in *, ss); - return ntohs(sin->sin_port); - } else if (ss->ss_family == AF_INET6) { - const struct sockaddr_in6 *sin6 - = ALIGNED_CAST(const struct sockaddr_in6 *, ss); - return ntohs(sin6->sin6_port); - } else { - OVS_NOT_REACHED(); - } + ovs_assert(sa_is_ip(sa)); + return ntohs(sa->sa_family == AF_INET + ? sin_cast(sa)->sin_port + : sin6_cast(sa)->sin6_port); } /* Returns true if 'name' is safe to include inside a network address field. @@ -1055,18 +1078,15 @@ is_safe_name(const char *name) } static void -ss_format_address__(const struct sockaddr_storage *ss, +sa_format_address__(const struct sockaddr *sa, const char *lbrack, const char *rbrack, struct ds *s) { - if (ss->ss_family == AF_INET) { - const struct sockaddr_in *sin - = ALIGNED_CAST(const struct sockaddr_in *, ss); - - ds_put_format(s, IP_FMT, IP_ARGS(sin->sin_addr.s_addr)); - } else if (ss->ss_family == AF_INET6) { - const struct sockaddr_in6 *sin6 - = ALIGNED_CAST(const struct sockaddr_in6 *, ss); + ovs_assert(sa_is_ip(sa)); + if (sa->sa_family == AF_INET) { + ds_put_format(s, IP_FMT, IP_ARGS(sin_cast(sa)->sin_addr.s_addr)); + } else { + const struct sockaddr_in6 *sin6 = sin6_cast(sa); ds_put_cstr(s, lbrack); ds_reserve(s, s->length + INET6_ADDRSTRLEN); @@ -1089,31 +1109,29 @@ ss_format_address__(const struct sockaddr_storage *ss, #endif ds_put_cstr(s, rbrack); - } else { - OVS_NOT_REACHED(); } } -/* Formats the IPv4 or IPv6 address in 'ss' into 's'. If 'ss' is an IPv6 +/* Formats the IPv4 or IPv6 address in 'sa' into 's'. If 'sa' is an IPv6 * address, puts square brackets around the address. */ void -ss_format_address(const struct sockaddr_storage *ss, struct ds *s) +sa_format_address(const struct sockaddr *sa, struct ds *s) { - ss_format_address__(ss, "[", "]", s); + sa_format_address__(sa, "[", "]", s); } -/* Formats the IPv4 or IPv6 address in 'ss' into 's'. Does not add square +/* Formats the IPv4 or IPv6 address in 'sa' into 's'. Does not add square * brackets around IPv6 addresses. */ void -ss_format_address_nobracks(const struct sockaddr_storage *ss, struct ds *s) +sa_format_address_nobracks(const struct sockaddr *sa, struct ds *s) { - ss_format_address__(ss, "", "", s); + sa_format_address__(sa, "", "", s); } size_t -ss_length(const struct sockaddr_storage *ss) +sa_length(const struct sockaddr *sa) { - switch (ss->ss_family) { + switch (sa->sa_family) { case AF_INET: return sizeof(struct sockaddr_in); @@ -1124,7 +1142,51 @@ ss_length(const struct sockaddr_storage *ss) OVS_NOT_REACHED(); } } + +/* sockaddr_storage helpers. */ +static const struct sockaddr * +sa_cast(const struct sockaddr_storage *ss) +{ + return ALIGNED_CAST(const struct sockaddr *, ss); +} + +bool +ss_is_ip(const struct sockaddr_storage *ss) +{ + return sa_is_ip(sa_cast(ss)); +} + +uint16_t +ss_get_port(const struct sockaddr_storage *ss) +{ + return sa_get_port(sa_cast(ss)); +} + +struct in6_addr +ss_get_address(const struct sockaddr_storage *ss) +{ + return sa_get_address(sa_cast(ss)); +} + +void +ss_format_address(const struct sockaddr_storage *ss, struct ds *s) +{ + sa_format_address(sa_cast(ss), s); +} + +void +ss_format_address_nobracks(const struct sockaddr_storage *ss, struct ds *s) +{ + sa_format_address_nobracks(sa_cast(ss), s); +} + +size_t +ss_length(const struct sockaddr_storage *ss) +{ + return sa_length(sa_cast(ss)); +} + /* For Windows socket calls, 'errno' is not set. One has to call * WSAGetLastError() to get the error number and then pass it to * this function to get the correct error string. diff --git a/lib/socket-util.h b/lib/socket-util.h index 239d3f22041c..6d386304dc3a 100644 --- a/lib/socket-util.h +++ b/lib/socket-util.h @@ -74,12 +74,24 @@ char *describe_fd(int fd); * in <netinet/ip.h> is used. */ #define DSCP_DEFAULT (IPTOS_PREC_INTERNETCONTROL >> 2) +/* Functions for working with sockaddr that might contain an IPv4 or + * IPv6 address. */ +bool sa_is_ip(const struct sockaddr *); +uint16_t sa_get_port(const struct sockaddr *); +struct in6_addr sa_get_address(const struct sockaddr *); +void sa_format_address(const struct sockaddr *, struct ds *); +void sa_format_address_nobracks(const struct sockaddr *, struct ds *); +size_t sa_length(const struct sockaddr *); + /* Functions for working with sockaddr_storage that might contain an IPv4 or * IPv6 address. */ +bool ss_is_ip(const struct sockaddr_storage *); uint16_t ss_get_port(const struct sockaddr_storage *); +struct in6_addr ss_get_address(const struct sockaddr_storage *); void ss_format_address(const struct sockaddr_storage *, struct ds *); void ss_format_address_nobracks(const struct sockaddr_storage *, struct ds *); size_t ss_length(const struct sockaddr_storage *); + const char *sock_strerror(int error); #ifndef _WIN32 -- 2.16.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev