@@ -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++;
}
}
@@ -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.
@@ -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
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 <blp@ovn.org> --- lib/netdev.c | 31 ++++-------- lib/socket-util.c | 138 +++++++++++++++++++++++++++++++++++++++--------------- lib/socket-util.h | 12 +++++ 3 files changed, 120 insertions(+), 61 deletions(-)