[RFC PATCH 00/10] Initial seastar ipv6 support

6 views
Skip to first unread message

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:01 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
Also at seastar-dev: calle/ipv6

* Adds ipv4 mirror types and/or embedding to address types in seastar.
* Changes posix stack to allow IPv6 addresses for bind/connect.
* Changes UDP interfaces to use socket_address (protocol agnostic address +
port) for connect/send/receive
* Changes UDP packets to return socket_address for packet src/dst
* Changes posix stack to allow ipv6 UDP.
* Changes RPC to allow ipv6 connectivity

Note that there are no explicit ipv6 tests yet (rfc). Tested on existing
unit tests (seastar + scylla)

Calle Wilund (10):
Add packed ipv6 address
Add ipv6_address support to inet_address
Add ipv6_addr
Add ipv6 support to socket_address
Make socket_address default constructor ipv4 any
Cleanup and de-inline some helper functions
Posix-stack: Add ipv6 support for tcp
UDP: redefine address used as socket_address
RPC: move log to cc file
RCP: make rpc use socket_address to support ipv6

include/seastar/net/api.hh | 52 +++------
include/seastar/net/inet_address.hh | 25 ++++-
include/seastar/net/ip.hh | 54 +++++++++-
include/seastar/net/posix-stack.hh | 6 +-
include/seastar/net/socket_defs.hh | 68 ++++++++++--
include/seastar/net/stack.hh | 4 +-
include/seastar/rpc/rpc.hh | 46 ++++----
src/net/inet_address.cc | 208 ++++++++++++++++++++++++++++++++----
src/net/ip.cc | 9 --
src/net/native-stack.cc | 4 +-
src/net/net.cc | 13 ++-
src/net/posix-stack.cc | 66 +++++++-----
src/net/stack.cc | 52 +++++++--
src/net/udp.cc | 8 +-
src/rpc/rpc.cc | 25 +++--
15 files changed, 480 insertions(+), 160 deletions(-)

--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:02 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
Corresponding to ipv4_address, packed to potentially allow embedding in
non-aligned wire structures.
---
include/seastar/net/ip.hh | 51 +++++++++++++++++++++++++++++++++++++-
src/net/inet_address.cc | 62 ++++++++++++++++++++++++++++++++++++++++++++++-
src/net/ip.cc | 9 -------
3 files changed, 111 insertions(+), 11 deletions(-)

diff --git a/include/seastar/net/ip.hh b/include/seastar/net/ip.hh
index 56cec7b3..e831b67e 100644
--- a/include/seastar/net/ip.hh
+++ b/include/seastar/net/ip.hh
@@ -105,7 +105,51 @@ struct ipv4_address {

static inline bool is_unspecified(ipv4_address addr) { return addr.ip == 0; }

-std::ostream& operator<<(std::ostream& os, ipv4_address a);
+std::ostream& operator<<(std::ostream& os, const ipv4_address& a);
+
+// IPv6
+struct ipv6_address {
+ using ipv6_bytes = std::array<uint8_t, 16>;
+
+ static_assert(alignof(ipv6_bytes) == 1);
+ static_assert(sizeof(ipv6_bytes) == 16);
+
+ ipv6_address();
+ explicit ipv6_address(const ::in6_addr&);
+ explicit ipv6_address(const ipv6_bytes&);
+ explicit ipv6_address(const std::string&);
+
+ // No need to use packed - we only store
+ // as byte array. If we want to read as
+ // uints or whatnot, we must copy
+ ipv6_bytes ip;
+
+ template <typename Adjuster>
+ auto adjust_endianness(Adjuster a) { return a(ip); }
+
+ bool operator==(const ipv6_address& y) {
+ return bytes() == y.bytes();
+ }
+ bool operator!=(const ipv6_address& y) {
+ return !(*this == y);
+ }
+
+ const ipv6_bytes& bytes() const {
+ return ip;
+ }
+
+ bool is_unspecified() const;
+
+ static ipv6_address read(const char*);
+ static ipv6_address consume(const char*& p);
+ void write(char* p) const;
+ void produce(char*& p) const;
+ static constexpr size_t size() {
+ return sizeof(ipv6_bytes);
+ }
+} __attribute__((packed));
+
+std::ostream& operator<<(std::ostream&, const ipv6_address&);

}

@@ -118,6 +162,11 @@ struct hash<seastar::net::ipv4_address> {
size_t operator()(seastar::net::ipv4_address a) const { return a.ip; }
};

+template <>
+struct hash<seastar::net::ipv6_address> {
+ size_t operator()(const seastar::net::ipv6_address&) const;
+};
+
}

namespace seastar {
diff --git a/src/net/inet_address.cc b/src/net/inet_address.cc
index d34f0f7c..89d27e80 100644
--- a/src/net/inet_address.cc
+++ b/src/net/inet_address.cc
@@ -21,7 +21,7 @@

#include <ostream>
#include <arpa/inet.h>
-
+#include <boost/functional/hash.hpp>
#include <seastar/net/inet_address.hh>
#include <seastar/net/socket_defs.hh>
#include <seastar/net/dns.hh>
@@ -112,6 +112,64 @@ const void * seastar::net::inet_address::data() const {
return &_in;
}

+seastar::net::ipv6_address::ipv6_address(const ::in6_addr& in) {
+ std::copy(std::begin(in.s6_addr), std::end(in.s6_addr), ip.begin());
+}
+
+seastar::net::ipv6_address::ipv6_address(const ipv6_bytes& in)
+ : ip(in)
+{}
+
+seastar::net::ipv6_address::ipv6_address()
+ : ipv6_address(::in6addr_any)
+{}
+
+seastar::net::ipv6_address::ipv6_address(const std::string& addr) {
+ if (!::inet_pton(AF_INET6, addr.c_str(), ip.data())) {
+ throw std::runtime_error(format("Wrong format for IPv6 address {}. Please ensure it's in colon-hex format",
+ addr));
+ }
+}
+
+seastar::net::ipv6_address seastar::net::ipv6_address::read(const char* s) {
+ auto* b = reinterpret_cast<const uint8_t *>(s);
+ ipv6_address in;
+ std::copy(b, b + ipv6_address::size(), in.ip.begin());
+ return in;
+}
+
+seastar::net::ipv6_address seastar::net::ipv6_address::consume(const char*& p) {
+ auto res = read(p);
+ p += size();
+ return res;
+}
+
+void seastar::net::ipv6_address::write(char* p) const {
+ std::copy(ip.begin(), ip.end(), p);
+}
+
+void seastar::net::ipv6_address::produce(char*& p) const {
+ write(p);
+ p += size();
+}
+
+bool seastar::net::ipv6_address::is_unspecified() const {
+ return std::all_of(ip.begin(), ip.end(), [](uint8_t b) { return b == 0; });
+}
+
+std::ostream& seastar::net::operator<<(std::ostream& os, const ipv4_address& a) {
+ auto ip = a.ip;
+ return fmt_print(os, "{:d}.{:d}.{:d}.{:d}",
+ (ip >> 24) & 0xff,
+ (ip >> 16) & 0xff,
+ (ip >> 8) & 0xff,
+ (ip >> 0) & 0xff);
+}
+
+std::ostream& seastar::net::operator<<(std::ostream& os, const ipv6_address& a) {
+ char buffer[64];
+ return os << ::inet_ntop(AF_INET6, a.ip.data(), buffer, sizeof(buffer));
+}

std::ostream& seastar::net::operator<<(std::ostream& os, const inet_address& addr) {
char buffer[64];
@@ -138,5 +196,7 @@ std::ostream& operator<<(std::ostream& os, const socket_address& a) {
;
}

+size_t std::hash<seastar::net::ipv6_address>::operator()(const seastar::net::ipv6_address& a) const {
+ return boost::hash_range(a.ip.begin(), a.ip.end());
}

diff --git a/src/net/ip.cc b/src/net/ip.cc
index 106e5d27..3b872d4b 100644
--- a/src/net/ip.cc
+++ b/src/net/ip.cc
@@ -31,15 +31,6 @@ namespace seastar {

namespace net {

-std::ostream& operator<<(std::ostream& os, ipv4_address a) {
- auto ip = a.ip;
- return fmt_print(os, "{:d}.{:d}.{:d}.{:d}",
- (ip >> 24) & 0xff,
- (ip >> 16) & 0xff,
- (ip >> 8) & 0xff,
- (ip >> 0) & 0xff);
-}
-
constexpr std::chrono::seconds ipv4::_frag_timeout;
constexpr uint32_t ipv4::_frag_low_thresh;
constexpr uint32_t ipv4::_frag_high_thresh;
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:03 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
---
include/seastar/net/inet_address.hh | 25 ++++++++++++++++---
src/net/inet_address.cc | 49 +++++++++++++++++++++++++++----------
2 files changed, 58 insertions(+), 16 deletions(-)

diff --git a/include/seastar/net/inet_address.hh b/include/seastar/net/inet_address.hh
index 849820fd..0d8d3c0e 100644
--- a/include/seastar/net/inet_address.hh
+++ b/include/seastar/net/inet_address.hh
@@ -34,6 +34,7 @@ namespace seastar {
namespace net {

struct ipv4_address;
+struct ipv6_address;

class unknown_host : public std::invalid_argument {
public:
@@ -42,7 +43,7 @@ class unknown_host : public std::invalid_argument {

class inet_address {
public:
- enum class family {
+ enum class family : sa_family_t {
INET = AF_INET, INET6 = AF_INET6
};
private:
@@ -64,9 +65,11 @@ class inet_address {
inet_address(const inet_address&) = default;

inet_address(const ipv4_address&);
+ inet_address(const ipv6_address&);

// throws iff ipv6
ipv4_address as_ipv4_address() const;
+ ipv6_address as_ipv6_address() const;

inet_address& operator=(const inet_address&) = default;
bool operator==(const inet_address&) const;
@@ -75,11 +78,20 @@ class inet_address {
return _in_family;
}

+ bool is_ipv6() const {
+ return _in_family == family::INET6;
+ }
+ bool is_ipv4() const {
+ return _in_family == family::INET;
+ }
+
size_t size() const;
const void * data() const;

- operator const ::in_addr&() const;
- operator const ::in6_addr&() const;
+ operator ::in_addr() const;
+ operator ::in6_addr() const;
+
+ operator ipv6_address() const;

future<sstring> hostname() const;
future<std::vector<sstring>> aliases() const;
@@ -95,3 +107,10 @@ std::ostream& operator<<(std::ostream&, const inet_address::family&);

}
}
+
+namespace std {
+template<>
+struct hash<seastar::net::inet_address> {
+ size_t operator()(const seastar::net::inet_address&) const;
+};
+}
diff --git a/src/net/inet_address.cc b/src/net/inet_address.cc
index 89d27e80..70badba2 100644
--- a/src/net/inet_address.cc
+++ b/src/net/inet_address.cc
@@ -27,10 +27,8 @@
#include <seastar/net/dns.hh>
#include <seastar/net/ip.hh>

-namespace seastar {
-
seastar::net::inet_address::inet_address()
- : inet_address(::in_addr{ 0, })
+ : inet_address(::in6_addr{ 0, })
{}

seastar::net::inet_address::inet_address(::in_addr i)
@@ -61,11 +59,13 @@ seastar::net::inet_address::inet_address(const ipv4_address& in)
{}

seastar::net::ipv4_address seastar::net::inet_address::as_ipv4_address() const {
- if (_in_family != family::INET) {
- // TODO: ipv4-compatible ipv6
- throw std::invalid_argument("Not an IPv4 address");
- }
- return ipv4_address(ntoh(_in.s_addr));
+ in_addr in = *this;
+ return ipv4_address(ntoh(in.s_addr));
+}
+
+seastar::net::ipv6_address seastar::net::inet_address::as_ipv6_address() const {
+ in6_addr in6 = *this;
+ return ipv6_address{in6};
}

bool seastar::net::inet_address::operator==(const inet_address& o) const {
@@ -83,20 +83,32 @@ bool seastar::net::inet_address::operator==(const inet_address& o) const {
}
}

-seastar::net::inet_address::operator const ::in_addr&() const {
+seastar::net::inet_address::operator ::in_addr() const {
if (_in_family != family::INET) {
- throw std::invalid_argument("Not an ipv4 address");
+ if (IN6_IS_ADDR_V4MAPPED(&_in6)) {
+ ::in_addr in;
+ in.s_addr = _in6.s6_addr32[3];
+ return in;
+ }
+ throw std::invalid_argument("Not an IPv4 address");
}
return _in;
}

-seastar::net::inet_address::operator const ::in6_addr&() const {
- if (_in_family != family::INET6) {
- throw std::invalid_argument("Not an ipv6 address");
+seastar::net::inet_address::operator ::in6_addr() const {
+ if (_in_family == family::INET) {
+ in6_addr in6 = IN6ADDR_ANY_INIT;
+ in6.s6_addr32[2] = ::htonl(0xffff);
+ in6.s6_addr32[3] = _in.s_addr;
+ return in6;
}
return _in6;
}

+seastar::net::inet_address::operator seastar::net::ipv6_address() const {
+ return as_ipv6_address();
+}
+
size_t seastar::net::inet_address::size() const {
switch (_in_family) {
case family::INET:
@@ -196,6 +208,17 @@ std::ostream& operator<<(std::ostream& os, const socket_address& a) {
;
}

+size_t std::hash<seastar::net::inet_address>::operator()(const seastar::net::inet_address& a) const {
+ switch (a.in_family()) {
+ case seastar::net::inet_address::family::INET:
+ return std::hash<seastar::net::ipv4_address>()(a.as_ipv4_address());
+ case seastar::net::inet_address::family::INET6:
+ return std::hash<seastar::net::ipv6_address>()(a.as_ipv6_address());
+ default:
+ return 0;
+ }
+}
+
size_t std::hash<seastar::net::ipv6_address>::operator()(const seastar::net::ipv6_address& a) const {
return boost::hash_range(a.ip.begin(), a.ip.end());
}
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:04 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
Like ipv4_addr, i.e. wraps address + port. Badly named, but akin to a
host endian sock_addr_in6.
---
include/seastar/net/ip.hh | 3 +++
include/seastar/net/socket_defs.hh | 21 ++++++++++++++++-
src/net/inet_address.cc | 46 ++++++++++++++++++++++++++++++++++++++
3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/include/seastar/net/ip.hh b/include/seastar/net/ip.hh
index e831b67e..57d3f08d 100644
--- a/include/seastar/net/ip.hh
+++ b/include/seastar/net/ip.hh
@@ -44,6 +44,8 @@

namespace seastar {

+struct ipv6_addr;
+
namespace net {

class ipv4;
@@ -118,6 +120,7 @@ struct ipv6_address {
explicit ipv6_address(const ::in6_addr&);
explicit ipv6_address(const ipv6_bytes&);
explicit ipv6_address(const std::string&);
+ ipv6_address(const ipv6_addr& addr);

// No need to use packed - we only store
// as byte array. If we want to read as
diff --git a/include/seastar/net/socket_defs.hh b/include/seastar/net/socket_defs.hh
index 055db041..e9327729 100644
--- a/include/seastar/net/socket_defs.hh
+++ b/include/seastar/net/socket_defs.hh
@@ -21,6 +21,7 @@
#pragma once

#include <iosfwd>
+#include <array>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <seastar/net/byteorder.hh>
@@ -76,8 +77,26 @@ struct ipv4_addr {
ip = net::ntoh(sa.u.in.sin_addr.s_addr);
port = net::ntoh(sa.u.in.sin_port);
}
+};
+
+struct ipv6_addr {
+ using ipv6_bytes = std::array<uint8_t, 16>;
+
+ ipv6_bytes ip;
+ uint16_t port;
+
+ ipv6_addr(const ipv6_bytes&, uint16_t port = 0);
+ ipv6_addr(uint16_t port = 0);
+ ipv6_addr(const std::string&);
+ ipv6_addr(const std::string&, uint16_t port);
+ ipv6_addr(const net::inet_address&, uint16_t = 0);
+ ipv6_addr(const ::in6_addr&, uint16_t = 0);
+ ipv6_addr(const ::sockaddr_in6&);

- ipv4_addr(socket_address &&sa) : ipv4_addr(sa) {}
+ bool is_ip_unspecified() const;
+ bool is_port_unspecified() const {
+ return port == 0;
+ }
};

}
diff --git a/src/net/inet_address.cc b/src/net/inet_address.cc
index 70badba2..7946b2d5 100644
--- a/src/net/inet_address.cc
+++ b/src/net/inet_address.cc
@@ -132,6 +132,10 @@ seastar::net::ipv6_address::ipv6_address(const ipv6_bytes& in)
: ip(in)
{}

+seastar::net::ipv6_address::ipv6_address(const ipv6_addr& addr)
+ : ipv6_address(addr.ip)
+{}
+
seastar::net::ipv6_address::ipv6_address()
: ipv6_address(::in6addr_any)
{}
@@ -183,6 +187,48 @@ std::ostream& seastar::net::operator<<(std::ostream& os, const ipv6_address& a)
return os << ::inet_ntop(AF_INET6, a.ip.data(), buffer, sizeof(buffer));
}

+seastar::ipv6_addr::ipv6_addr(const ipv6_bytes& b, uint16_t p)
+ : ip(b), port(p)
+{}
+
+seastar::ipv6_addr::ipv6_addr(uint16_t p)
+ : ipv6_addr(net::inet_address(), p)
+{}
+
+seastar::ipv6_addr::ipv6_addr(const ::in6_addr& in6, uint16_t p)
+ : ipv6_addr(net::ipv6_address(in6).bytes(), p)
+{}
+
+seastar::ipv6_addr::ipv6_addr(const std::string& s)
+ : ipv6_addr([&] {
+ auto lc = s.find_last_of(']');
+ auto cp = s.find_first_of(':', lc);
+ auto port = cp != std::string::npos ? std::stoul(s.substr(cp + 1)) : 0;
+ auto ss = lc != std::string::npos ? s.substr(1, lc - 1) : s;
+ return ipv6_addr(net::ipv6_address(ss).bytes(), uint16_t(port));
+ }())
+{}
+
+seastar::ipv6_addr::ipv6_addr(const std::string& s, uint16_t p)
+ : ipv6_addr(net::ipv6_address(s).bytes(), p)
+{}
+
+seastar::ipv6_addr::ipv6_addr(const net::inet_address& i, uint16_t p)
+ : ipv6_addr(i.as_ipv6_address().bytes(), p)
+{}
+
+seastar::ipv6_addr::ipv6_addr(const ::sockaddr_in6& s)
+ : ipv6_addr(s.sin6_addr, net::ntoh(s.sin6_port))
+{}
+
+seastar::ipv6_addr::ipv6_addr(const socket_address& s)
+ : ipv6_addr(s.as_posix_sockaddr_in6())
+{}
+
+bool seastar::ipv6_addr::is_ip_unspecified() const {
+ return std::all_of(ip.begin(), ip.end(), [](uint8_t b) { return b == 0; });
+}
+
std::ostream& seastar::net::operator<<(std::ostream& os, const inet_address& addr) {
char buffer[64];
return os << inet_ntop(int(addr.in_family()), addr.data(), buffer, sizeof(buffer));
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:04 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
---
include/seastar/net/socket_defs.hh | 45 +++++++++++++++++++++++++++------
src/net/inet_address.cc | 51 +++++++++++++++++++++++++++++++++++---
src/net/net.cc | 13 +++++++---
src/net/stack.cc | 40 +++++++++++++++++++++++++-----
4 files changed, 127 insertions(+), 22 deletions(-)

diff --git a/include/seastar/net/socket_defs.hh b/include/seastar/net/socket_defs.hh
index e9327729..5a3a0f0d 100644
--- a/include/seastar/net/socket_defs.hh
+++ b/include/seastar/net/socket_defs.hh
@@ -28,7 +28,12 @@

namespace seastar {

+namespace net {
+class inet_address;
+}
+
struct ipv4_addr;
+struct ipv6_addr;

class socket_address {
public:
@@ -36,16 +41,29 @@ class socket_address {
::sockaddr_storage sas;
::sockaddr sa;
::sockaddr_in in;
+ ::sockaddr_in6 in6;
} u;
- socket_address(sockaddr_in sa) {
+ socket_address(const sockaddr_in& sa) {
u.in = sa;
}
+ socket_address(const sockaddr_in6& sa) {
+ u.in6 = sa;
+ }
socket_address(ipv4_addr);
+ socket_address(const ipv6_addr&);
+ socket_address(const net::inet_address&, uint16_t p = 0);
socket_address() = default;
::sockaddr& as_posix_sockaddr() { return u.sa; }
::sockaddr_in& as_posix_sockaddr_in() { return u.in; }
+ ::sockaddr_in6& as_posix_sockaddr_in6() { return u.in6; }
const ::sockaddr& as_posix_sockaddr() const { return u.sa; }
const ::sockaddr_in& as_posix_sockaddr_in() const { return u.in; }
+ const ::sockaddr_in6& as_posix_sockaddr_in6() const { return u.in6; }
+
+ socket_address(uint32_t, uint16_t p = 0);
+
+ net::inet_address addr() const;
+ ::in_port_t port() const;

bool operator==(const socket_address&) const;
};
@@ -58,10 +76,6 @@ enum class transport {
};


-namespace net {
-class inet_address;
-}
-
struct ipv4_addr {
uint32_t ip;
uint16_t port;
@@ -72,10 +86,14 @@ struct ipv4_addr {
ipv4_addr(const std::string &addr);
ipv4_addr(const std::string &addr, uint16_t port);
ipv4_addr(const net::inet_address&, uint16_t);
+ ipv4_addr(const socket_address &);
+ ipv4_addr(const ::in_addr&, uint16_t = 0);

- ipv4_addr(const socket_address &sa) {
- ip = net::ntoh(sa.u.in.sin_addr.s_addr);
- port = net::ntoh(sa.u.in.sin_port);
+ bool is_ip_unspecified() const {
+ return ip == 0;
+ }
+ bool is_port_unspecified() const {
+ return port == 0;
}
};

@@ -92,6 +110,7 @@ struct ipv6_addr {
ipv6_addr(const net::inet_address&, uint16_t = 0);
ipv6_addr(const ::in6_addr&, uint16_t = 0);
ipv6_addr(const ::sockaddr_in6&);
+ ipv6_addr(const socket_address&);

bool is_ip_unspecified() const;
bool is_port_unspecified() const {
@@ -99,4 +118,14 @@ struct ipv6_addr {
}
};

+std::ostream& operator<<(std::ostream&, const ipv4_addr&);
+std::ostream& operator<<(std::ostream&, const ipv6_addr&);
+
+}
+
+namespace std {
+template<>
+struct hash<seastar::socket_address> {
+ size_t operator()(const seastar::socket_address&) const;
+};
}
diff --git a/src/net/inet_address.cc b/src/net/inet_address.cc
index 7946b2d5..133ac04d 100644
--- a/src/net/inet_address.cc
+++ b/src/net/inet_address.cc
@@ -229,6 +229,25 @@ bool seastar::ipv6_addr::is_ip_unspecified() const {
return std::all_of(ip.begin(), ip.end(), [](uint8_t b) { return b == 0; });
}

+seastar::socket_address::socket_address(const net::inet_address& a, uint16_t p)
+ : socket_address(a.is_ipv6() ? socket_address(ipv6_addr(a, p)) : socket_address(ipv4_addr(a, p)))
+{}
+
+seastar::net::inet_address seastar::socket_address::addr() const {
+ switch (as_posix_sockaddr().sa_family) {
+ case AF_INET:
+ return net::inet_address(as_posix_sockaddr_in().sin_addr);
+ case AF_INET6:
+ return net::inet_address(as_posix_sockaddr_in6().sin6_addr);
+ default:
+ return net::inet_address();
+ }
+}
+
+::in_port_t seastar::socket_address::port() const {
+ return net::ntoh(u.in.sin_port);
+}
+
std::ostream& seastar::net::operator<<(std::ostream& os, const inet_address& addr) {
char buffer[64];
return os << inet_ntop(int(addr.in_family()), addr.data(), buffer, sizeof(buffer));
@@ -248,10 +267,28 @@ std::ostream& seastar::net::operator<<(std::ostream& os, const inet_address::fam
return os;
}

-std::ostream& operator<<(std::ostream& os, const socket_address& a) {
- return os << seastar::net::inet_address(a.as_posix_sockaddr_in().sin_addr)
- << ":" << ntohs(a.u.in.sin_port)
- ;
+std::ostream& seastar::operator<<(std::ostream& os, const socket_address& a) {
+ auto addr = a.addr();
+ // CMH. maybe skip brackets for ipv4-mapped
+ auto bracket = addr.in_family() == seastar::net::inet_address::family::INET6;
+
+ if (bracket) {
+ os << '[';
+ }
+ os << addr;
+ if (bracket) {
+ os << ']';
+ }
+
+ return os << ':' << ntohs(a.u.in.sin_port);
+}
+
+std::ostream& seastar::operator<<(std::ostream& os, const ipv4_addr& a) {
+ return os << seastar::socket_address(a);
+}
+
+std::ostream& seastar::operator<<(std::ostream& os, const ipv6_addr& a) {
+ return os << seastar::socket_address(a);
}

size_t std::hash<seastar::net::inet_address>::operator()(const seastar::net::inet_address& a) const {
@@ -265,6 +302,12 @@ size_t std::hash<seastar::net::inet_address>::operator()(const seastar::net::ine
}
}

+size_t std::hash<seastar::socket_address>::operator()(const seastar::socket_address& a) const {
+ auto h = std::hash<seastar::net::inet_address>()(a.addr());
+ boost::hash_combine(h, a.as_posix_sockaddr_in().sin_port);
+ return h;
+}
+
size_t std::hash<seastar::net::ipv6_address>::operator()(const seastar::net::ipv6_address& a) const {
return boost::hash_range(a.ip.begin(), a.ip.end());
}
diff --git a/src/net/net.cc b/src/net/net.cc
index c32e669e..30fb3833 100644
--- a/src/net/net.cc
+++ b/src/net/net.cc
@@ -49,10 +49,15 @@ ipv4_addr::ipv4_addr(const std::string &addr) {
ipv4_addr::ipv4_addr(const std::string &addr, uint16_t port_) : ip(boost::asio::ip::address_v4::from_string(addr).to_ulong()), port(port_) {}

ipv4_addr::ipv4_addr(const net::inet_address& a, uint16_t port)
- : ipv4_addr([&a] {
- ::in_addr in = a;
- return net::ntoh(in.s_addr);
-}(), port)
+ : ipv4_addr(::in_addr(a), port)
+{}
+
+ipv4_addr::ipv4_addr(const socket_address &sa)
+ : ipv4_addr(sa.addr(), sa.port())
+{}
+
+ipv4_addr::ipv4_addr(const ::in_addr& in, uint16_t p)
+ : ip(net::ntoh(in.s_addr)), port(p)
{}

namespace net {
diff --git a/src/net/stack.cc b/src/net/stack.cc
index 0193d579..fa172c61 100644
--- a/src/net/stack.cc
+++ b/src/net/stack.cc
@@ -151,15 +151,43 @@ void server_socket::abort_accept() {
}

socket_address::socket_address(ipv4_addr addr)
- : socket_address(make_ipv4_address(addr))
-{}
+{
+ u.in.sin_family = AF_INET;
+ u.in.sin_port = htons(addr.port);
+ u.in.sin_addr.s_addr = htonl(addr.ip);
+}

+socket_address::socket_address(const ipv6_addr& addr)
+{
+ u.in6.sin6_family = AF_INET6;
+ u.in6.sin6_port = htons(addr.port);
+ std::copy(addr.ip.begin(), addr.ip.end(), u.in6.sin6_addr.s6_addr);
+}
+
+socket_address::socket_address(uint32_t ipv4, uint16_t p)
+ : socket_address(make_ipv4_address(ipv4, p))
+{}

bool socket_address::operator==(const socket_address& a) const {
- // TODO: handle ipv6
- return std::tie(u.in.sin_family, u.in.sin_port, u.in.sin_addr.s_addr)
- == std::tie(a.u.in.sin_family, a.u.in.sin_port,
- a.u.in.sin_addr.s_addr);
+ if (u.sa.sa_family != a.u.sa.sa_family) {
+ return false;
+ }
+ if (u.in.sin_port != a.u.in.sin_port) {
+ return false;
+ }
+ switch (u.sa.sa_family) {
+ case AF_INET:
+ return u.in.sin_addr.s_addr == a.u.in.sin_addr.s_addr;
+ case AF_INET6:
+ break;
+ default:
+ return false;
+ }
+
+ auto& in1 = as_posix_sockaddr_in6();
+ auto& in2 = a.as_posix_sockaddr_in6();
+
+ return IN6_ARE_ADDR_EQUAL(&in1, &in2);
}

}
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:05 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
---
include/seastar/net/socket_defs.hh | 2 +-
src/net/stack.cc | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/include/seastar/net/socket_defs.hh b/include/seastar/net/socket_defs.hh
index 5a3a0f0d..e905219f 100644
--- a/include/seastar/net/socket_defs.hh
+++ b/include/seastar/net/socket_defs.hh
@@ -52,7 +52,7 @@ class socket_address {
socket_address(ipv4_addr);
socket_address(const ipv6_addr&);
socket_address(const net::inet_address&, uint16_t p = 0);
- socket_address() = default;
+ socket_address();
::sockaddr& as_posix_sockaddr() { return u.sa; }
::sockaddr_in& as_posix_sockaddr_in() { return u.in; }
::sockaddr_in6& as_posix_sockaddr_in6() { return u.in6; }
diff --git a/src/net/stack.cc b/src/net/stack.cc
index fa172c61..34e8e9cd 100644
--- a/src/net/stack.cc
+++ b/src/net/stack.cc
@@ -150,6 +150,10 @@ void server_socket::abort_accept() {
_aborted = true;
}

+socket_address::socket_address()
+ : socket_address(ipv4_addr())
+{}
+
socket_address::socket_address(ipv4_addr addr)
{
u.in.sin_family = AF_INET;
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:06 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
---
include/seastar/net/api.hh | 38 ++++++++++----------------------------
1 file changed, 10 insertions(+), 28 deletions(-)

diff --git a/include/seastar/net/api.hh b/include/seastar/net/api.hh
index a4d9fd34..b9c03915 100644
--- a/include/seastar/net/api.hh
+++ b/include/seastar/net/api.hh
@@ -36,42 +36,24 @@

namespace seastar {

-static inline
-bool is_ip_unspecified(ipv4_addr &addr) {
- return addr.ip == 0;
-}
-
-static inline
-bool is_port_unspecified(ipv4_addr &addr) {
- return addr.port == 0;
+inline
+bool is_ip_unspecified(const ipv4_addr& addr) {
+ return addr.is_ip_unspecified();
}

-static inline
-std::ostream& operator<<(std::ostream &os, ipv4_addr addr) {
- fmt_print(os, "{:d}.{:d}.{:d}.{:d}",
- (addr.ip >> 24) & 0xff,
- (addr.ip >> 16) & 0xff,
- (addr.ip >> 8) & 0xff,
- (addr.ip) & 0xff);
- return os << ":" << addr.port;
+inline
+bool is_port_unspecified(const ipv4_addr& addr) {
+ return addr.is_port_unspecified();
}

-static inline
-socket_address make_ipv4_address(ipv4_addr addr) {
- socket_address sa;
- sa.u.in.sin_family = AF_INET;
- sa.u.in.sin_port = htons(addr.port);
- sa.u.in.sin_addr.s_addr = htonl(addr.ip);
- return sa;
+inline
+socket_address make_ipv4_address(const ipv4_addr& addr) {
+ return socket_address(addr);
}

inline
socket_address make_ipv4_address(uint32_t ip, uint16_t port) {
- socket_address sa;
- sa.u.in.sin_family = AF_INET;
- sa.u.in.sin_port = htons(port);
- sa.u.in.sin_addr.s_addr = htonl(ip);
- return sa;
+ return make_ipv4_address(ipv4_addr(ip, port));
}

namespace net {
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:07 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
---
include/seastar/net/posix-stack.hh | 4 ++--
src/net/posix-stack.cc | 14 +++++++-------
2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/include/seastar/net/posix-stack.hh b/include/seastar/net/posix-stack.hh
index bb203044..41677006 100644
--- a/include/seastar/net/posix-stack.hh
+++ b/include/seastar/net/posix-stack.hh
@@ -129,8 +129,8 @@ class posix_ap_server_socket_impl : public server_socket_impl {
socket_address addr;
connection(pollable_fd xfd, socket_address xaddr) : fd(std::move(xfd)), addr(xaddr) {}
};
- static thread_local std::unordered_map<::sockaddr_in, promise<connected_socket, socket_address>> sockets;
- static thread_local std::unordered_multimap<::sockaddr_in, connection> conn_q;
+ static thread_local std::unordered_map<socket_address, promise<connected_socket, socket_address>> sockets;
+ static thread_local std::unordered_multimap<socket_address, connection> conn_q;
socket_address _sa;
public:
explicit posix_ap_server_socket_impl(socket_address sa) : _sa(sa) {}
diff --git a/src/net/posix-stack.cc b/src/net/posix-stack.cc
index a9225943..92010b5b 100644
--- a/src/net/posix-stack.cc
+++ b/src/net/posix-stack.cc
@@ -234,7 +234,7 @@ posix_server_socket_impl<Transport>::abort_accept() {

template <transport Transport>
future<connected_socket, socket_address> posix_ap_server_socket_impl<Transport>::accept() {
- auto conni = conn_q.find(_sa.as_posix_sockaddr_in());
+ auto conni = conn_q.find(_sa);
if (conni != conn_q.end()) {
connection c = std::move(conni->second);
conn_q.erase(conni);
@@ -247,7 +247,7 @@ future<connected_socket, socket_address> posix_ap_server_socket_impl<Transport>:
}
} else {
try {
- auto i = sockets.emplace(std::piecewise_construct, std::make_tuple(_sa.as_posix_sockaddr_in()), std::make_tuple());
+ auto i = sockets.emplace(std::piecewise_construct, std::make_tuple(_sa), std::make_tuple());
assert(i.second);
return i.first->second.get_future();
} catch (...) {
@@ -259,7 +259,7 @@ future<connected_socket, socket_address> posix_ap_server_socket_impl<Transport>:
template <transport Transport>
void
posix_ap_server_socket_impl<Transport>::abort_accept() {
- conn_q.erase(_sa.as_posix_sockaddr_in());
+ conn_q.erase(_sa);
auto i = sockets.find(_sa.as_posix_sockaddr_in());
if (i != sockets.end()) {
i->second.set_exception(std::system_error(ECONNABORTED, std::system_category()));
@@ -287,7 +287,7 @@ posix_reuseport_server_socket_impl<Transport>::abort_accept() {
template <transport Transport>
void
posix_ap_server_socket_impl<Transport>::move_connected_socket(socket_address sa, pollable_fd fd, socket_address addr, conntrack::handle cth) {
- auto i = sockets.find(sa.as_posix_sockaddr_in());
+ auto i = sockets.find(sa);
if (i != sockets.end()) {
try {
std::unique_ptr<connected_socket_impl> csi(new posix_connected_socket_impl<Transport>(make_lw_shared(std::move(fd)), std::move(cth)));
@@ -297,7 +297,7 @@ posix_ap_server_socket_impl<Transport>::move_connected_socket(socket_address sa,
}
sockets.erase(i);
} else {
- conn_q.emplace(std::piecewise_construct, std::make_tuple(sa.as_posix_sockaddr_in()), std::make_tuple(std::move(fd), std::move(addr)));
+ conn_q.emplace(std::piecewise_construct, std::make_tuple(sa), std::make_tuple(std::move(fd), std::move(addr)));
}
}

@@ -371,9 +371,9 @@ ::seastar::socket posix_network_stack::socket() {
}

template<transport Transport>
-thread_local std::unordered_map<::sockaddr_in, promise<connected_socket, socket_address>> posix_ap_server_socket_impl<Transport>::sockets;
+thread_local std::unordered_map<socket_address, promise<connected_socket, socket_address>> posix_ap_server_socket_impl<Transport>::sockets;
template<transport Transport>
-thread_local std::unordered_multimap<::sockaddr_in, typename posix_ap_server_socket_impl<Transport>::connection> posix_ap_server_socket_impl<Transport>::conn_q;
+thread_local std::unordered_multimap<socket_address, typename posix_ap_server_socket_impl<Transport>::connection> posix_ap_server_socket_impl<Transport>::conn_q;

server_socket
posix_ap_network_stack::listen(socket_address sa, listen_options opt) {
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:08 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
UPD interface/packets are hardcoded to use ipv4_addr as dest/source
addresses. Redefine this to instead use socket_address, which contains
all the multiplexing needed to handle optional ipv6.

Since socket_address also translated transparently to ipv4_addr,
existing programs should continue to work as before (more or less).

Adds actual ipv6 support to posix stack UDP.
---
include/seastar/net/api.hh | 14 +++++-----
include/seastar/net/posix-stack.hh | 2 +-
include/seastar/net/stack.hh | 4 +--
src/net/native-stack.cc | 4 +--
src/net/posix-stack.cc | 52 +++++++++++++++++++++++---------------
src/net/stack.cc | 8 +++---
src/net/udp.cc | 8 +++---
7 files changed, 52 insertions(+), 40 deletions(-)

diff --git a/include/seastar/net/api.hh b/include/seastar/net/api.hh
index b9c03915..34ed4c33 100644
--- a/include/seastar/net/api.hh
+++ b/include/seastar/net/api.hh
@@ -84,8 +84,8 @@ class get_impl;
class udp_datagram_impl {
public:
virtual ~udp_datagram_impl() {};
- virtual ipv4_addr get_src() = 0;
- virtual ipv4_addr get_dst() = 0;
+ virtual socket_address get_src() = 0;
+ virtual socket_address get_dst() = 0;
virtual uint16_t get_dst_port() = 0;
virtual packet& get_data() = 0;
};
@@ -95,8 +95,8 @@ class udp_datagram final {
std::unique_ptr<udp_datagram_impl> _impl;
public:
udp_datagram(std::unique_ptr<udp_datagram_impl>&& impl) : _impl(std::move(impl)) {};
- ipv4_addr get_src() { return _impl->get_src(); }
- ipv4_addr get_dst() { return _impl->get_dst(); }
+ socket_address get_src() { return _impl->get_src(); }
+ socket_address get_dst() { return _impl->get_dst(); }
uint16_t get_dst_port() { return _impl->get_dst_port(); }
packet& get_data() { return _impl->get_data(); }
};
@@ -113,8 +113,8 @@ class udp_channel {
udp_channel& operator=(udp_channel&&);

future<udp_datagram> receive();
- future<> send(ipv4_addr dst, const char* msg);
- future<> send(ipv4_addr dst, packet p);
+ future<> send(const socket_address& dst, const char* msg);
+ future<> send(const socket_address& dst, packet p);
bool is_closed() const;
void close();
};
@@ -279,7 +279,7 @@ class network_stack {
return socket().connect(sa, local, proto);
}
virtual ::seastar::socket socket() = 0;
- virtual net::udp_channel make_udp_channel(ipv4_addr addr = {}) = 0;
+ virtual net::udp_channel make_udp_channel(const socket_address& = {}) = 0;
virtual future<> initialize() {
return make_ready_future();
}
diff --git a/include/seastar/net/posix-stack.hh b/include/seastar/net/posix-stack.hh
index 41677006..dbd77556 100644
--- a/include/seastar/net/posix-stack.hh
+++ b/include/seastar/net/posix-stack.hh
@@ -174,7 +174,7 @@ class posix_network_stack : public network_stack {
explicit posix_network_stack(boost::program_options::variables_map opts) : _reuseport(engine().posix_reuseport_available()) {}
virtual server_socket listen(socket_address sa, listen_options opts) override;
virtual ::seastar::socket socket() override;
- virtual net::udp_channel make_udp_channel(ipv4_addr addr) override;
+ virtual net::udp_channel make_udp_channel(const socket_address&) override;
static future<std::unique_ptr<network_stack>> create(boost::program_options::variables_map opts) {
return make_ready_future<std::unique_ptr<network_stack>>(std::unique_ptr<network_stack>(new posix_network_stack(opts)));
}
diff --git a/include/seastar/net/stack.hh b/include/seastar/net/stack.hh
index 11b65f70..a7aeac68 100644
--- a/include/seastar/net/stack.hh
+++ b/include/seastar/net/stack.hh
@@ -61,8 +61,8 @@ class udp_channel_impl {
public:
virtual ~udp_channel_impl() {};
virtual future<udp_datagram> receive() = 0;
- virtual future<> send(ipv4_addr dst, const char* msg) = 0;
- virtual future<> send(ipv4_addr dst, packet p) = 0;
+ virtual future<> send(const socket_address& dst, const char* msg) = 0;
+ virtual future<> send(const socket_address& dst, packet p) = 0;
virtual bool is_closed() const = 0;
virtual void close() = 0;
};
diff --git a/src/net/native-stack.cc b/src/net/native-stack.cc
index 678e96e4..5812a19f 100644
--- a/src/net/native-stack.cc
+++ b/src/net/native-stack.cc
@@ -151,7 +151,7 @@ class native_network_stack : public network_stack {
explicit native_network_stack(boost::program_options::variables_map opts, std::shared_ptr<device> dev);
virtual server_socket listen(socket_address sa, listen_options opt) override;
virtual ::seastar::socket socket() override;
- virtual udp_channel make_udp_channel(ipv4_addr addr) override;
+ virtual udp_channel make_udp_channel(const socket_address& addr) override;
virtual future<> initialize() override;
static future<std::unique_ptr<network_stack>> create(boost::program_options::variables_map opts) {
if (engine().cpu_id() == 0) {
@@ -169,7 +169,7 @@ class native_network_stack : public network_stack {
thread_local promise<std::unique_ptr<network_stack>> native_network_stack::ready_promise;

udp_channel
-native_network_stack::make_udp_channel(ipv4_addr addr) {
+native_network_stack::make_udp_channel(const socket_address& addr) {
return _inet.get_udp().make_channel(addr);
}

diff --git a/src/net/posix-stack.cc b/src/net/posix-stack.cc
index 92010b5b..4ba51f0a 100644
--- a/src/net/posix-stack.cc
+++ b/src/net/posix-stack.cc
@@ -392,7 +392,10 @@ posix_ap_network_stack::listen(socket_address sa, listen_options opt) {

struct cmsg_with_pktinfo {
struct cmsghdrcmh;
- struct in_pktinfo pktinfo;
+ union {
+ struct in_pktinfo pktinfo;
+ struct in6_pktinfo pkt6info;
+ };
};

class posix_udp_channel : public udp_channel_impl {
@@ -434,8 +437,8 @@ class posix_udp_channel : public udp_channel_impl {
_hdr.msg_namelen = sizeof(_dst.u.sas);
}

- void prepare(ipv4_addr dst, packet p) {
- _dst = make_ipv4_address(dst);
+ void prepare(const socket_address& dst, packet p) {
+ _dst = dst;
_p = std::move(p);
_iovecs = to_iovec(_p);
_hdr.msg_iov = _iovecs.data();
@@ -443,27 +446,27 @@ class posix_udp_channel : public udp_channel_impl {
}
};
std::unique_ptr<pollable_fd> _fd;
- ipv4_addr _address;
+ socket_address _address;
recv_ctx _recv;
send_ctx _send;
bool _closed;
public:
- posix_udp_channel(ipv4_addr bind_address)
+ posix_udp_channel(const socket_address& bind_address)
: _closed(false) {
- auto sa = make_ipv4_address(bind_address);
+ auto sa = bind_address;
file_desc fd = file_desc::socket(sa.u.sa.sa_family, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
fd.setsockopt(SOL_IP, IP_PKTINFO, true);
if (engine().posix_reuseport_available()) {
fd.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1);
}
fd.bind(sa.u.sa, sizeof(sa.u.sas));
- _address = ipv4_addr(fd.get_address());
+ _address = fd.get_address();
_fd = std::make_unique<pollable_fd>(std::move(fd));
}
virtual ~posix_udp_channel() { if (!_closed) close(); };
virtual future<udp_datagram> receive() override;
- virtual future<> send(ipv4_addr dst, const char *msg);
- virtual future<> send(ipv4_addr dst, packet p);
+ virtual future<> send(const socket_address& dst, const char *msg) override;
+ virtual future<> send(const socket_address& dst, packet p) override;
virtual void close() override {
_closed = true;
_fd->abort_reader(std::make_exception_ptr(std::system_error(EPIPE, std::system_category())));
@@ -473,13 +476,13 @@ class posix_udp_channel : public udp_channel_impl {
virtual bool is_closed() const override { return _closed; }
};

-future<> posix_udp_channel::send(ipv4_addr dst, const char *message) {
+future<> posix_udp_channel::send(const socket_address& dst, const char *message) {
auto len = strlen(message);
- return _fd->sendto(make_ipv4_address(dst), message, len)
+ return _fd->sendto(dst, message, len)
.then([len] (size_t size) { assert(size == len); });
}

-future<> posix_udp_channel::send(ipv4_addr dst, packet p) {
+future<> posix_udp_channel::send(const socket_address& dst, packet p) {
auto len = p.len();
_send.prepare(dst, std::move(p));
return _fd->sendmsg(&_send._hdr)
@@ -487,20 +490,20 @@ future<> posix_udp_channel::send(ipv4_addr dst, packet p) {
}

udp_channel
-posix_network_stack::make_udp_channel(ipv4_addr addr) {
+posix_network_stack::make_udp_channel(const socket_address& addr) {
return udp_channel(std::make_unique<posix_udp_channel>(addr));
}

class posix_datagram : public udp_datagram_impl {
private:
- ipv4_addr _src;
- ipv4_addr _dst;
+ socket_address _src;
+ socket_address _dst;
packet _p;
public:
- posix_datagram(ipv4_addr src, ipv4_addr dst, packet p) : _src(src), _dst(dst), _p(std::move(p)) {}
- virtual ipv4_addr get_src() override { return _src; }
- virtual ipv4_addr get_dst() override { return _dst; }
- virtual uint16_t get_dst_port() override { return _dst.port; }
+ posix_datagram(const socket_address& src, const socket_address& dst, packet p) : _src(src), _dst(dst), _p(std::move(p)) {}
+ virtual socket_address get_src() override { return _src; }
+ virtual socket_address get_dst() override { return _dst; }
+ virtual uint16_t get_dst_port() override { return _dst.port(); }
virtual packet& get_data() override { return _p; }
};

@@ -508,7 +511,16 @@ future<udp_datagram>
posix_udp_channel::receive() {
_recv.prepare();
return _fd->recvmsg(&_recv._hdr).then([this] (size_t size) {
- auto dst = ipv4_addr(_recv._cmsg.pktinfo.ipi_addr.s_addr, _address.port);
+ socket_address dst;
+ for (auto* cmsg = CMSG_FIRSTHDR(&_recv._hdr); cmsg != nullptr; cmsg = CMSG_NXTHDR(&_recv._hdr, cmsg)) {
+ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
+ dst = ipv4_addr(reinterpret_cast<const in_pktinfo*>(CMSG_DATA(cmsg))->ipi_addr, _address.port());
+ break;
+ } else if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+ dst = ipv6_addr(reinterpret_cast<const in6_pktinfo*>(CMSG_DATA(cmsg))->ipi6_addr, _address.port());
+ break;
+ }
+ }
return make_ready_future<udp_datagram>(udp_datagram(std::make_unique<posix_datagram>(
_recv._src_addr, dst, packet(fragment{_recv._buffer, size}, make_deleter([buf = _recv._buffer] { delete[] buf; })))));
}).handle_exception([p = _recv._buffer](auto ep) {
diff --git a/src/net/stack.cc b/src/net/stack.cc
index 34e8e9cd..2ea18f92 100644
--- a/src/net/stack.cc
+++ b/src/net/stack.cc
@@ -40,12 +40,12 @@ future<net::udp_datagram> net::udp_channel::receive() {
return _impl->receive();
}

-future<> net::udp_channel::send(ipv4_addr dst, const char* msg) {
- return _impl->send(std::move(dst), msg);
+future<> net::udp_channel::send(const socket_address& dst, const char* msg) {
+ return _impl->send(dst, msg);
}

-future<> net::udp_channel::send(ipv4_addr dst, packet p) {
- return _impl->send(std::move(dst), std::move(p));
+future<> net::udp_channel::send(const socket_address& dst, packet p) {
+ return _impl->send(dst, std::move(p));
}

bool net::udp_channel::is_closed() const {
diff --git a/src/net/udp.cc b/src/net/udp.cc
index 9b679a4f..97dabfe2 100644
--- a/src/net/udp.cc
+++ b/src/net/udp.cc
@@ -50,11 +50,11 @@ class native_datagram : public udp_datagram_impl {
_dst = to_ipv4_addr(dst, h.dst_port);
}

- virtual ipv4_addr get_src() override {
+ virtual socket_address get_src() override {
return _src;
};

- virtual ipv4_addr get_dst() override {
+ virtual socket_address get_dst() override {
return _dst;
};

@@ -93,11 +93,11 @@ class native_channel : public udp_channel_impl {
return _state->_queue.pop_eventually();
}

- virtual future<> send(ipv4_addr dst, const char* msg) override {
+ virtual future<> send(const socket_address& dst, const char* msg) override {
return send(dst, packet::from_static_data(msg, strlen(msg)));
}

- virtual future<> send(ipv4_addr dst, packet p) override {
+ virtual future<> send(const socket_address& dst, packet p) override {
auto len = p.len();
return _state->wait_for_send_buffer(len).then([this, dst, p = std::move(p), len] () mutable {
p = packet(std::move(p), make_deleter([s = _state, len] { s->complete_send(len); }));
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:09 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
---
include/seastar/rpc/rpc.hh | 12 +++---------
src/rpc/rpc.cc | 13 +++++++++++++
2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/include/seastar/rpc/rpc.hh b/include/seastar/rpc/rpc.hh
index 4a3c8ada..55dff5bd 100644
--- a/include/seastar/rpc/rpc.hh
+++ b/include/seastar/rpc/rpc.hh
@@ -169,17 +169,11 @@ class logger {
_logger = std::move(l);
}

- void operator()(const client_info& info, id_type msg_id, const sstring& str) const {
- log(to_sstring("client ") + inet_ntoa(info.addr.as_posix_sockaddr_in().sin_addr) + " msg_id " + to_sstring(msg_id) + ": " + str);
- }
+ void operator()(const client_info& info, id_type msg_id, const sstring& str) const;

- void operator()(const client_info& info, const sstring& str) const {
- log(to_sstring("client ") + inet_ntoa(info.addr.as_posix_sockaddr_in().sin_addr) + ": " + str);
- }
+ void operator()(const client_info& info, const sstring& str) const;

- void operator()(ipv4_addr addr, const sstring& str) const {
- log(to_sstring("client ") + inet_ntoa(in_addr{net::ntoh(addr.ip)}) + ": " + str);
- }
+ void operator()(ipv4_addr addr, const sstring& str) const;
};

class connection {
diff --git a/src/rpc/rpc.cc b/src/rpc/rpc.cc
index 4e37af83..8d70452d 100644
--- a/src/rpc/rpc.cc
+++ b/src/rpc/rpc.cc
@@ -4,6 +4,19 @@
namespace seastar {

namespace rpc {
+
+ void logger::operator()(const client_info& info, id_type msg_id, const sstring& str) const {
+ log(to_sstring("client ") + inet_ntoa(info.addr.as_posix_sockaddr_in().sin_addr) + " msg_id " + to_sstring(msg_id) + ": " + str);
+ }
+
+ void logger::operator()(const client_info& info, const sstring& str) const {
+ log(to_sstring("client ") + inet_ntoa(info.addr.as_posix_sockaddr_in().sin_addr) + ": " + str);
+ }
+
+ void logger::operator()(ipv4_addr addr, const sstring& str) const {
+ log(to_sstring("client ") + inet_ntoa(in_addr{net::ntoh(addr.ip)}) + ": " + str);
+ }
+
no_wait_type no_wait;

constexpr size_t snd_buf::chunk_size;
--
2.14.5

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 5:29:10 AM1/16/19
to seastar-dev@googlegroups.com, Calle Wilund
---
include/seastar/rpc/rpc.hh | 36 ++++++++++++++++++------------------
src/rpc/rpc.cc | 20 ++++++++++----------
2 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/include/seastar/rpc/rpc.hh b/include/seastar/rpc/rpc.hh
index 55dff5bd..b59f58cd 100644
--- a/include/seastar/rpc/rpc.hh
+++ b/include/seastar/rpc/rpc.hh
@@ -173,7 +173,7 @@ class logger {

void operator()(const client_info& info, const sstring& str) const;

- void operator()(ipv4_addr addr, const sstring& str) const;
+ void operator()(const socket_address& addr, const sstring& str) const;
};

class connection {
@@ -287,7 +287,7 @@ class connection {
}
xshard_connection_ptr get_stream(connection_id id) const;
void register_stream(connection_id id, xshard_connection_ptr c);
- virtual ipv4_addr peer_address() const = 0;
+ virtual socket_address peer_address() const = 0;

const logger& get_logger() const {
return _logger;
@@ -360,7 +360,7 @@ class client : public rpc::connection, public weakly_referencable<client> {
};
private:
std::unordered_map<id_type, std::unique_ptr<reply_handler_base>> _outstanding;
- ipv4_addr _server_addr;
+ socket_address _server_addr;
client_options _options;
compat::optional<shared_promise<>> _client_negotiated = shared_promise<>();
weak_ptr<client> _parent; // for stream clients
@@ -386,8 +386,8 @@ class client : public rpc::connection, public weakly_referencable<client> {
* @param addr the remote address identifying this client
* @param local the local address of this client
*/
- client(const logger& l, void* s, ipv4_addr addr, ipv4_addr local = ipv4_addr());
- client(const logger& l, void* s, client_options options, ipv4_addr addr, ipv4_addr local = ipv4_addr());
+ client(const logger& l, void* s, const socket_address& addr, const socket_address& local = {});
+ client(const logger& l, void* s, client_options options, const socket_address& addr, const socket_address& local = {});

/**
* Create client object which will attempt to connect to the remote address using the
@@ -397,8 +397,8 @@ class client : public rpc::connection, public weakly_referencable<client> {
* @param local the local address of this client
* @param socket the socket object use to connect to the remote address
*/
- client(const logger& l, void* s, socket socket, ipv4_addr addr, ipv4_addr local = ipv4_addr());
- client(const logger& l, void* s, client_options options, socket socket, ipv4_addr addr, ipv4_addr local = ipv4_addr());
+ client(const logger& l, void* s, socket socket, const socket_address& addr, const socket_address& local = {});
+ client(const logger& l, void* s, client_options options, socket socket, const socket_address& addr, const socket_address& local = {});

stats get_stats() const;
stats& get_stats_internal() {
@@ -410,7 +410,7 @@ class client : public rpc::connection, public weakly_referencable<client> {
future<> stop();
void abort_all_streams();
void deregister_this_stream();
- ipv4_addr peer_address() const override {
+ socket_address peer_address() const override {
return _server_addr;
}
future<> await_connection() {
@@ -484,8 +484,8 @@ class server {
stats& get_stats_internal() {
return _stats;
}
- ipv4_addr peer_address() const override {
- return ipv4_addr(_info.addr);
+ socket_address peer_address() const override {
+ return _info.addr;
}
// Resources will be released when this goes out of scope
future<resource_permit> wait_for_resources(size_t memory_consumed, compat::optional<rpc_clock_type::time_point> timeout) {
@@ -518,8 +518,8 @@ class server {
uint64_t _next_client_id = 1;

public:
- server(protocol_base* proto, ipv4_addr addr, resource_limits memory_limit = resource_limits());
- server(protocol_base* proto, server_options opts, ipv4_addr addr, resource_limits memory_limit = resource_limits());
+ server(protocol_base* proto, const socket_address& addr, resource_limits memory_limit = resource_limits());
+ server(protocol_base* proto, server_options opts, const socket_address& addr, resource_limits memory_limit = resource_limits());
server(protocol_base* proto, server_socket, resource_limits memory_limit = resource_limits(), server_options opts = server_options{});
server(protocol_base* proto, server_options opts, server_socket, resource_limits memory_limit = resource_limits());
void accept();
@@ -560,9 +560,9 @@ class protocol : public protocol_base {
public:
class server : public rpc::server {
public:
- server(protocol& proto, ipv4_addr addr, resource_limits memory_limit = resource_limits()) :
+ server(protocol& proto, const socket_address& addr, resource_limits memory_limit = resource_limits()) :
rpc::server(&proto, addr, memory_limit) {}
- server(protocol& proto, server_options opts, ipv4_addr addr, resource_limits memory_limit = resource_limits()) :
+ server(protocol& proto, server_options opts, const socket_address& addr, resource_limits memory_limit = resource_limits()) :
rpc::server(&proto, opts, addr, memory_limit) {}
server(protocol& proto, server_socket socket, resource_limits memory_limit = resource_limits(), server_options opts = server_options{}) :
rpc::server(&proto, std::move(socket), memory_limit) {}
@@ -577,9 +577,9 @@ class protocol : public protocol_base {
* @param addr the remote address identifying this client
* @param local the local address of this client
*/
- client(protocol& p, ipv4_addr addr, ipv4_addr local = ipv4_addr()) :
+ client(protocol& p, const socket_address& addr, const socket_address& local = {}) :
rpc::client(p.get_logger(), &p._serializer, addr, local) {}
- client(protocol& p, client_options options, ipv4_addr addr, ipv4_addr local = ipv4_addr()) :
+ client(protocol& p, client_options options, const socket_address& addr, const socket_address& local = {}) :
rpc::client(p.get_logger(), &p._serializer, options, addr, local) {}

/**
@@ -590,9 +590,9 @@ class protocol : public protocol_base {
* @param local the local address of this client
* @param socket the socket object use to connect to the remote address
*/
- client(protocol& p, socket socket, ipv4_addr addr, ipv4_addr local = ipv4_addr()) :
+ client(protocol& p, socket socket, const socket_address& addr, const socket_address& local = {}) :
rpc::client(p.get_logger(), &p._serializer, std::move(socket), addr, local) {}
- client(protocol& p, client_options options, socket socket, ipv4_addr addr, ipv4_addr local = ipv4_addr()) :
+ client(protocol& p, client_options options, socket socket, const socket_address& addr, const socket_address& local = {}) :
rpc::client(p.get_logger(), &p._serializer, options, std::move(socket), addr, local) {}
};

diff --git a/src/rpc/rpc.cc b/src/rpc/rpc.cc
index 8d70452d..0ac1571a 100644
--- a/src/rpc/rpc.cc
+++ b/src/rpc/rpc.cc
@@ -6,15 +6,15 @@ namespace seastar {
namespace rpc {

void logger::operator()(const client_info& info, id_type msg_id, const sstring& str) const {
- log(to_sstring("client ") + inet_ntoa(info.addr.as_posix_sockaddr_in().sin_addr) + " msg_id " + to_sstring(msg_id) + ": " + str);
+ log(format("client {} msg_id {}: {}", info.addr, msg_id, str));
}

void logger::operator()(const client_info& info, const sstring& str) const {
- log(to_sstring("client ") + inet_ntoa(info.addr.as_posix_sockaddr_in().sin_addr) + ": " + str);
+ (*this)(info.addr, str);
}

- void logger::operator()(ipv4_addr addr, const sstring& str) const {
- log(to_sstring("client ") + inet_ntoa(in_addr{net::ntoh(addr.ip)}) + ": " + str);
+ void logger::operator()(const socket_address& addr, const sstring& str) const {
+ log(format("client {}: {}", addr, str));
}

no_wait_type no_wait;
@@ -621,7 +621,7 @@ namespace rpc {
}
}

- client::client(const logger& l, void* s, client_options ops, socket socket, ipv4_addr addr, ipv4_addr local)
+ client::client(const logger& l, void* s, client_options ops, socket socket, const socket_address& addr, const socket_address& local)
: rpc::connection(l, s), _socket(std::move(socket)), _server_addr(addr), _options(ops) {
_socket.connect(addr, local).then([this, ops = std::move(ops)] (connected_socket fd) {
fd.set_nodelay(ops.tcp_nodelay);
@@ -711,15 +711,15 @@ namespace rpc {
});
}

- client::client(const logger& l, void* s, ipv4_addr addr, ipv4_addr local)
+ client::client(const logger& l, void* s, const socket_address& addr, const socket_address& local)
: client(l, s, client_options{}, engine().net().socket(), addr, local)
{}

- client::client(const logger& l, void* s, client_options options, ipv4_addr addr, ipv4_addr local)
+ client::client(const logger& l, void* s, client_options options, const socket_address& addr, const socket_address& local)
: client(l, s, options, engine().net().socket(), addr, local)
{}

- client::client(const logger& l, void* s, socket socket, ipv4_addr addr, ipv4_addr local)
+ client::client(const logger& l, void* s, socket socket, const socket_address& addr, const socket_address& local)
: client(l, s, client_options{}, std::move(socket), addr, local)
{}

@@ -944,11 +944,11 @@ namespace rpc {

thread_local std::unordered_map<streaming_domain_type, server*> server::_servers;

- server::server(protocol_base* proto, ipv4_addr addr, resource_limits limits)
+ server::server(protocol_base* proto, const socket_address& addr, resource_limits limits)
: server(proto, engine().listen(addr, listen_options{true}), limits, server_options{})
{}

- server::server(protocol_base* proto, server_options opts, ipv4_addr addr, resource_limits limits)
+ server::server(protocol_base* proto, server_options opts, const socket_address& addr, resource_limits limits)
: server(proto, engine().listen(addr, listen_options{true, opts.load_balancing_algorithm}), limits, opts)
{}

--
2.14.5

Avi Kivity

<avi@scylladb.com>
unread,
Jan 16, 2019, 6:24:19 AM1/16/19
to Calle Wilund, seastar-dev@googlegroups.com
Could be inlined. Appreciate the attention to compile time but trivial
function should be inlinable.


> + explicit ipv6_address(const std::string&);
> +
> + // No need to use packed - we only store
> + // as byte array. If we want to read as
> + // uints or whatnot, we must copy
> + ipv6_bytes ip;
> +
> + template <typename Adjuster>
> + auto adjust_endianness(Adjuster a) { return a(ip); }
> +
> + bool operator==(const ipv6_address& y) {
> + return bytes() == y.bytes();
> + }

const


> + bool operator!=(const ipv6_address& y) {
> + return !(*this == y);
> + }


const


> +
> + const ipv6_bytes& bytes() const {
> + return ip;
> + }
> +
> + bool is_unspecified() const;
> +
> + static ipv6_address read(const char*);
> + static ipv6_address consume(const char*& p);
> + void write(char* p) const;
> + void produce(char*& p) const;
> + static constexpr size_t size() {
> + return sizeof(ipv6_bytes);
> + }
> +} __attribute__((packed));
> +
> +std::ostream& operator<<(std::ostream&, const ipv6_address&);
>
> }
>
> @@ -118,6 +162,11 @@ struct hash<seastar::net::ipv4_address> {
> size_t operator()(seastar::net::ipv4_address a) const { return a.ip; }
> };
>
> +template <>
> +struct hash<seastar::net::ipv6_address> {
> + size_t operator()(const seastar::net::ipv6_address&) const;


This may as well be inline.

Avi Kivity

<avi@scylladb.com>
unread,
Jan 16, 2019, 6:32:16 AM1/16/19
to Calle Wilund, seastar-dev@googlegroups.com

On 16/01/2019 12.27, Calle Wilund wrote:
Didn't I see this in patch 1?

Avi Kivity

<avi@scylladb.com>
unread,
Jan 16, 2019, 6:34:35 AM1/16/19
to Calle Wilund, seastar-dev@googlegroups.com

RCP -> RPC

On 16/01/2019 12.27, Calle Wilund wrote:

Avi Kivity

<avi@scylladb.com>
unread,
Jan 16, 2019, 6:35:19 AM1/16/19
to Calle Wilund, seastar-dev@googlegroups.com

On 16/01/2019 12.27, Calle Wilund wrote:
> Also at seastar-dev: calle/ipv6
>
> * Adds ipv4 mirror types and/or embedding to address types in seastar.
> * Changes posix stack to allow IPv6 addresses for bind/connect.
> * Changes UDP interfaces to use socket_address (protocol agnostic address +
> port) for connect/send/receive
> * Changes UDP packets to return socket_address for packet src/dst
> * Changes posix stack to allow ipv6 UDP.
> * Changes RPC to allow ipv6 connectivity


Looks good, a couple of nitpicks only. I presume we have source
compatibility because socket_address constructors are not explicit?

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 7:02:23 AM1/16/19
to Avi Kivity, seastar-dev@googlegroups.com

Den 2019-01-16 kl. 12:35, skrev Avi Kivity:
>
> On 16/01/2019 12.27, Calle Wilund wrote:
>> Also at seastar-dev: calle/ipv6
>>
>> * Adds ipv4 mirror types and/or embedding to address types in seastar.
>> * Changes posix stack to allow IPv6 addresses for bind/connect.
>> * Changes UDP interfaces to use socket_address (protocol agnostic
>> address +
>>    port) for connect/send/receive
>> * Changes UDP packets to return socket_address for packet src/dst
>> * Changes posix stack to allow ipv6 UDP.
>> * Changes RPC to allow ipv6 connectivity
>
>
> Looks good, a couple of nitpicks only. I presume we have source
> compatibility because socket_address constructors are not explicit?
>
Yes. Seastar apps, tests and scylla all compile and run without
modification.

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 7:06:31 AM1/16/19
to Avi Kivity, seastar-dev@googlegroups.com
It is also include file dependencies. Various functions are in cc files
to avoid having headers included in others.
For example, the constructor using ::in6_addr uses <algo> etc.
Uses boost hash. I'm really focusing in not bloating include swamp or
inline junk, because all these are
pretty much cold paths. (Hash is a perhaps a little hot, but only really
from socket_address::hash, and
that can do inline in any case. (Same file).

Calle Wilund

<calle@scylladb.com>
unread,
Jan 16, 2019, 7:07:39 AM1/16/19
to Avi Kivity, seastar-dev@googlegroups.com
The code is somewhat duplicated between types. Could make this use the
other or vice versa.

Avi Kivity

<avi@scylladb.com>
unread,
Jan 16, 2019, 7:09:19 AM1/16/19
to Calle Wilund, seastar-dev@googlegroups.com
Yes. I guess for anything except UDP addresses are not very important
since they are only used during connection time. So we can keep it
out-of-line for now.
Ok. If we needed to speed it up we'd code unrolled math instead of using
the boost stuff.

Avi Kivity

<avi@scylladb.com>
unread,
Jan 16, 2019, 7:10:54 AM1/16/19
to Calle Wilund, seastar-dev@googlegroups.com
Oh, that was ipv4_address and this is ipv4_addr. Those names are truly
bad, but fixing the up and/or code deduplication need not be part of this.



Alexander Gallego

<gallego.alexx@gmail.com>
unread,
Jan 16, 2019, 10:52:59 AM1/16/19
to seastar-dev
Reply all
Reply to author
Forward
0 new messages