Skip to content

Commit

Permalink
issue-1444: move netlink helpers to core/libs/netlink (#2471)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmyagkov authored Nov 15, 2024
1 parent 98d2c20 commit f82fa2c
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 180 deletions.
185 changes: 12 additions & 173 deletions cloud/blockstore/libs/nbd/netlink_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@
#include "utils.h"

#include <cloud/storage/core/libs/diagnostics/logging.h>
#include <cloud/storage/core/libs/netlink/socket.h>

#include <linux/nbd-netlink.h>

#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>
#include <netlink/netlink.h>

#include <util/generic/scope.h>
#include <util/stream/mem.h>

Expand All @@ -19,177 +16,18 @@ namespace {

using namespace NThreading;

using TResponseHandler = std::function<int(genlmsghdr*)>;

////////////////////////////////////////////////////////////////////////////////

constexpr TStringBuf NBD_DEVICE_SUFFIX = "/dev/nbd";

////////////////////////////////////////////////////////////////////////////////

class TNetlinkSocket
{
private:
nl_sock* Socket;
int Family;

public:
TNetlinkSocket()
{
Socket = nl_socket_alloc();

if (Socket == nullptr) {
throw TServiceError(E_FAIL) << "unable to allocate netlink socket";
}

if (int err = genl_connect(Socket)) {
nl_socket_free(Socket);
throw TServiceError(E_FAIL)
<< "unable to connect to generic netlink socket: "
<< nl_geterror(err);
}

Family = genl_ctrl_resolve(Socket, "nbd");

if (Family < 0) {
nl_socket_free(Socket);
throw TServiceError(E_FAIL)
<< "unable to resolve nbd netlink family: "
<< nl_geterror(Family);
}
}

~TNetlinkSocket()
{
nl_socket_free(Socket);
}

int GetFamily() const
{
return Family;
}

template <typename F>
void SetCallback(nl_cb_type type, F func)
{
auto arg = std::make_unique<TResponseHandler>(std::move(func));

if (int err = nl_socket_modify_cb(
Socket,
type,
NL_CB_CUSTOM,
TNetlinkSocket::ResponseHandler,
arg.get()))
{
throw TServiceError(E_FAIL)
<< "unable to set socket callback: " << nl_geterror(err);
}
arg.release();
}

static int ResponseHandler(nl_msg* msg, void* arg)
{
auto func = std::unique_ptr<TResponseHandler>(
static_cast<TResponseHandler*>(arg));

return (*func)(static_cast<genlmsghdr*>(nlmsg_data(nlmsg_hdr(msg))));
}

void Send(nl_msg* message)
{
if (int err = nl_send_auto(Socket, message); err < 0) {
throw TServiceError(E_FAIL)
<< "send error: " << nl_geterror(err);
}
if (int err = nl_wait_for_ack(Socket)) {
// this is either recv error, or an actual error message received
// from the kernel
throw TServiceError(E_FAIL)
<< "recv error: " << nl_geterror(err);
}
}
};

////////////////////////////////////////////////////////////////////////////////

class TNestedAttribute
{
private:
nl_msg* Message;
nlattr* Attribute;

public:
TNestedAttribute(nl_msg* message, int attribute)
: Message(message)
{
Attribute = nla_nest_start(message, attribute);
if (!Attribute) {
throw TServiceError(E_FAIL) << "unable to nest attribute";
}
}

~TNestedAttribute()
{
nla_nest_end(Message, Attribute);
}
};

////////////////////////////////////////////////////////////////////////////////

class TNetlinkMessage
{
private:
nl_msg* Message;

public:
TNetlinkMessage(int family, int command)
{
Message = nlmsg_alloc();
if (Message == nullptr) {
throw TServiceError(E_FAIL) << "unable to allocate message";
}
genlmsg_put(
Message,
NL_AUTO_PORT,
NL_AUTO_SEQ,
family,
0, // hdrlen
0, // flags
command,
0); // version
}

~TNetlinkMessage()
{
nlmsg_free(Message);
}

operator nl_msg*() const
{
return Message;
}

template <typename T>
void Put(int attribute, T data)
{
if (int err = nla_put(Message, attribute, sizeof(T), &data)) {
throw TServiceError(E_FAIL) << "unable to put attribute "
<< attribute << ": " << nl_geterror(err);
}
}

TNestedAttribute Nest(int attribute)
{
return TNestedAttribute(Message, attribute);
}
};

////////////////////////////////////////////////////////////////////////////////

class TNetlinkDevice final
: public IDevice
, public std::enable_shared_from_this<TNetlinkDevice>
{
using TNetlinkMessage = NCloud::NNetlink::TMessage;
using TNetlinkSocket = NCloud::NNetlink::TSocket;
private:
const ILoggingServicePtr Logging;
const TNetworkAddress ConnectAddress;
Expand Down Expand Up @@ -231,7 +69,7 @@ class TNetlinkDevice final
void Disconnect();
void DoConnect(bool connected);

int StatusHandler(genlmsghdr* header);
int StatusHandler(nl_msg* nlmsg);
};

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -309,7 +147,7 @@ TFuture<NProto::TError> TNetlinkDevice::Stop(bool deleteDevice)
TFuture<NProto::TError> TNetlinkDevice::Resize(ui64 deviceSizeInBytes)
{
try {
TNetlinkSocket socket;
TNetlinkSocket socket("nbd");
TNetlinkMessage message(socket.GetFamily(), NBD_CMD_RECONFIGURE);

message.Put(NBD_ATTR_INDEX, DeviceIndex);
Expand Down Expand Up @@ -373,11 +211,11 @@ void TNetlinkDevice::DisconnectSocket()
// or reconfigure (if Reconfigure == true) specified device
void TNetlinkDevice::Connect()
{
TNetlinkSocket socket;
TNetlinkSocket socket("nbd");
socket.SetCallback(
NL_CB_VALID,
[device = shared_from_this()] (auto* header) {
return device->StatusHandler(header);
[device = shared_from_this()](auto* nlmsg) {
return device->StatusHandler(nlmsg);
});

TNetlinkMessage message(socket.GetFamily(), NBD_CMD_STATUS);
Expand All @@ -389,7 +227,7 @@ void TNetlinkDevice::Disconnect()
{
STORAGE_INFO("disconnect " << DeviceName);

TNetlinkSocket socket;
TNetlinkSocket socket("nbd");
TNetlinkMessage message(socket.GetFamily(), NBD_CMD_DISCONNECT);
message.Put(NBD_ATTR_INDEX, DeviceIndex);
socket.Send(message);
Expand All @@ -410,7 +248,7 @@ void TNetlinkDevice::DoConnect(bool connected)
STORAGE_INFO("connect " << DeviceName);
}

TNetlinkSocket socket;
TNetlinkSocket socket("nbd");
TNetlinkMessage message(socket.GetFamily(), command);

const auto& info = Handler->GetExportInfo();
Expand Down Expand Up @@ -448,8 +286,9 @@ void TNetlinkDevice::DoConnect(bool connected)
}
}

int TNetlinkDevice::StatusHandler(genlmsghdr* header)
int TNetlinkDevice::StatusHandler(nl_msg* nlmsg)
{
auto header = static_cast<genlmsghdr*>(nlmsg_data(nlmsg_hdr(nlmsg)));
nlattr* attr[NBD_ATTR_MAX + 1] = {};
nlattr* deviceItem[NBD_DEVICE_ITEM_MAX + 1] = {};
nlattr* device[NBD_DEVICE_ATTR_MAX + 1] = {};
Expand Down
8 changes: 1 addition & 7 deletions cloud/blockstore/libs/nbd/ya.make
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
LIBRARY()

LICENSE_RESTRICTION_EXCEPTIONS(
contrib/restricted/libnl/lib/nl-3
contrib/restricted/libnl/lib/nl-genl-3
)

SRCS(
binary_reader.cpp
binary_writer.cpp
Expand All @@ -30,9 +25,8 @@ PEERDIR(
cloud/blockstore/libs/diagnostics
cloud/blockstore/libs/service
cloud/storage/core/libs/coroutine
cloud/storage/core/libs/netlink
contrib/libs/linux-headers
contrib/restricted/libnl/lib/nl-3
contrib/restricted/libnl/lib/nl-genl-3
library/cpp/coroutine/engine
library/cpp/coroutine/listener
library/cpp/deprecated/atomic
Expand Down
55 changes: 55 additions & 0 deletions cloud/storage/core/libs/netlink/message.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "message.h"

namespace NCloud::NNetlink {

TNestedAttribute::TNestedAttribute(nl_msg* message, int attribute)
: Message(message)
{
Attribute = nla_nest_start(message, attribute);
if (!Attribute) {
throw TServiceError(E_FAIL) << "unable to nest attribute";
}
}

TNestedAttribute::~TNestedAttribute()
{
nla_nest_end(Message, Attribute);
}

TMessage::TMessage(int family, int command)
{
Message = nlmsg_alloc();
if (Message == nullptr) {
throw TServiceError(E_FAIL) << "unable to allocate message";
}
genlmsg_put(
Message,
NL_AUTO_PORT,
NL_AUTO_SEQ,
family,
0, // hdrlen
0, // flags
command,
1); // version
}

TMessage::~TMessage()
{
nlmsg_free(Message);
}

TNestedAttribute TMessage::Nest(int attribute)
{
return TNestedAttribute(Message, attribute);
}

void TMessage::Put(int attribute, void* data, size_t size)
{
if (int err = nla_put(Message, attribute, size, data)) {
throw TServiceError(E_FAIL)
<< "unable to put attribute " << attribute << ": "
<< nl_geterror(err);
}
}

} // namespace NCloud::NNetlink
48 changes: 48 additions & 0 deletions cloud/storage/core/libs/netlink/message.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <cloud/storage/core/libs/common/error.h>

#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>

namespace NCloud::NNetlink {

////////////////////////////////////////////////////////////////////////////////

class TNestedAttribute
{
private:
nl_msg* Message;
nlattr* Attribute;

public:
TNestedAttribute(nl_msg* message, int attribute);
~TNestedAttribute();
};

////////////////////////////////////////////////////////////////////////////////

class TMessage
{
private:
nl_msg* Message;

public:
TMessage(int family, int command);
~TMessage();

operator nl_msg*() const
{
return Message;
}

TNestedAttribute Nest(int attribute);

void Put(int attribute, void* data, size_t size);

template <typename T>
void Put(int attribute, T data)
{
Put(attribute, &data, sizeof(T));
}
};

} // namespace NCloud::NNetlink
Loading

0 comments on commit f82fa2c

Please sign in to comment.