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