2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-27 15:18:06 +00:00

socket-util: Add more functions for IPv[46] sockaddr and sockaddr_storage.

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>
Acked-by: Mark Michelson <mmichels@redhat.com>
This commit is contained in:
Ben Pfaff
2018-04-13 09:51:37 -07:00
parent 0b043300db
commit 93b7faf1c7
3 changed files with 121 additions and 62 deletions

View File

@@ -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. */
/* Returns the IPv4 or IPv6 port in 'ss'. */
uint16_t
ss_get_port(const struct sockaddr_storage *ss)
static struct sockaddr_in *
sin_cast(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();
}
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 'sa'. */
uint16_t
sa_get_port(const struct sockaddr *sa)
{
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.