#include "proxy_link.h"
#include "proxy_manager.h"
+#include "proxy_requests.h"
#include "proxy_helpers.h"
#include "proxy_log.h"
return len;
}
+static void proxy_link_negotiate_v0_prepare(proxy_link_negotiate_v0_t *v0,
+ bool legacy)
+{
+ uint16_t version, min_version;
+
+ if (legacy) {
+ version = v0->legacy.version;
+ min_version = v0->legacy.min_version;
+ v0->version = version;
+ v0->min_version = min_version;
+
+ /* This comes from the client. It doesn't support any operation,
+ * just callbacks. */
+ v0->num_ops = 0;
+ if ((v0->flags & PROXY_NEG_V0_OPS) == 0) {
+ v0->num_cbks = LIBCEPHFSD_CBK_LL_NONBLOCKING_FSYNC + 1;
+ v0->flags = 0;
+ }
+ } else if ((v0->flags & PROXY_NEG_V0_OPS) == 0) {
+ version = v0->legacy.version;
+ min_version = v0->legacy.min_version;
+ v0->version = version;
+ v0->min_version = min_version;
+ v0->num_ops = LIBCEPHFSD_OP_LL_NONBLOCKING_FSYNC + 1;
+ /* This comes from the daemon. It doesn't support any callback,
+ * just operations. */
+ v0->num_cbks = 0;
+ v0->flags = 0;
+ }
+}
+
+static void proxy_link_negotiate_v0_legacy(proxy_link_negotiate_t *src,
+ proxy_link_negotiate_t *dst)
+{
+ memcpy(dst, src, sizeof(proxy_link_negotiate_t));
+
+ dst->v0.legacy.version = src->v0.version;
+ dst->v0.legacy.min_version = src->v0.min_version;
+}
+
static int32_t proxy_link_negotiate_read(proxy_link_t *link, int32_t sd,
- proxy_link_negotiate_t *neg)
+ proxy_link_negotiate_t *neg,
+ bool legacy)
{
char buffer[128];
char *ptr;
return err;
}
+ proxy_link_negotiate_v0_prepare(&neg->v0, legacy);
+
ptr += sizeof(neg->v0);
size = neg->v0.size;
static int32_t proxy_link_negotiate_check(proxy_link_negotiate_t *local,
proxy_link_negotiate_t *remote,
- proxy_link_negotiate_cbk_t cbk)
+ proxy_link_negotiate_cbk_t cbk,
+ bool client)
{
uint32_t supported, enabled;
int32_t err;
local->v0.size = remote->v0.size;
}
+ if (client) {
+ local->v0.num_ops = remote->v0.num_ops;
+ } else {
+ local->v0.num_cbks = remote->v0.num_cbks;
+ }
+
+ local->v0.flags &= remote->v0.flags;
+
if (remote->v0.version == 0) {
/* Legacy peer. If we require any feature, the peer won't
* support it, so we can't continue */
proxy_link_negotiate_t *neg,
proxy_link_negotiate_cbk_t cbk)
{
- proxy_link_negotiate_t remote;
+ proxy_link_negotiate_t legacy, remote;
int32_t err;
- err = proxy_link_write(link, sd, neg, neg->v0.size);
+ /* Convert the negotiation structure to legacy for the first
+ * nogotiation packet. */
+ proxy_link_negotiate_v0_legacy(neg, &legacy);
+
+ err = proxy_link_write(link, sd, &legacy, legacy.v0.size);
if (err < 0) {
return err;
}
- err = proxy_link_negotiate_read(link, sd, &remote);
+ err = proxy_link_negotiate_read(link, sd, &remote, false);
if (err < 0) {
return err;
}
- err = proxy_link_negotiate_check(neg, &remote, cbk);
+ err = proxy_link_negotiate_check(neg, &remote, cbk, true);
if (err < 0) {
return err;
}
proxy_link_negotiate_t *neg,
proxy_link_negotiate_cbk_t cbk)
{
- proxy_link_negotiate_t remote;
+ proxy_link_negotiate_t remote, legacy;
int32_t err;
- err = proxy_link_negotiate_read(link, sd, &remote);
+ err = proxy_link_negotiate_read(link, sd, &remote, true);
if (err < 0) {
return err;
}
- err = proxy_link_negotiate_check(neg, &remote, cbk);
+ err = proxy_link_negotiate_check(neg, &remote, cbk, false);
if (err < 0) {
return err;
}
- err = proxy_link_write(link, sd, neg, neg->v0.size);
+ if ((remote.v0.flags & PROXY_NEG_V0_OPS) == 0) {
+ proxy_link_negotiate_v0_legacy(neg, &legacy);
+ err = proxy_link_write(link, sd, &legacy, legacy.v0.size);
+ } else {
+ err = proxy_link_write(link, sd, neg, neg->v0.size);
+ }
if (err < 0) {
return err;
}
if (version.minor == LIBCEPHFSD_MINOR) {
/* The server doesn't support negotiation. */
- proxy_link_negotiate_init_v0(&legacy, 0, 0);
+ proxy_link_negotiate_init_v0(&legacy, 0, 0,
+ LIBCEPHFSD_OP_LL_NONBLOCKING_FSYNC + 1, 0);
- return proxy_link_negotiate_check(neg, &legacy, cbk);
+ return proxy_link_negotiate_check(neg, &legacy, cbk, true);
}
if (version.minor != LIBCEPHFSD_MINOR_NEG) {
}
if (size == 0) {
- proxy_link_negotiate_init_v0(&legacy, 0, 0);
+ proxy_link_negotiate_init_v0(&legacy, 0, 0, 0,
+ LIBCEPHFSD_CBK_LL_NONBLOCKING_FSYNC + 1);
- err = proxy_link_negotiate_check(neg, &legacy, cbk);
+ err = proxy_link_negotiate_check(neg, &legacy, cbk, false);
if (err < 0) {
return err;
}
#include <sys/socket.h>
#include <sys/un.h>
+#include <endian.h>
#include "proxy.h"
/* The maximum supported protocol version. */
#define PROXY_LINK_PROTOCOL_VERSION PROXY_PROTOCOL_V1
+/* Flags for the proxy_link_negotiate_v0_t structure. */
+enum {
+ /* If set, the v0 structure is using the new layout. */
+ PROXY_NEG_V0_OPS = 1
+};
+
/* Version 0 structure will be used to handle legacy clients that don't support
* negotiation. */
typedef struct _proxy_link_negotiate_v0 {
* NEG_VERSION_SIZE() to avoid alignement issues. */
uint16_t size;
- /* Version of the negotiation structure. */
- uint16_t version;
-
- /* Minimum version that the peer needs to support to proceed. */
- uint16_t min_version;
-
- /* Reserved. Must be 0. */
- uint16_t flags;
+ /* We keep the previous structure definition as 'legacy' for backward
+ * compatibility. It will be used in the initial negotiation request
+ * sent by the client. The flag PROXY_NEG_V0_OPS indicates if the
+ * new layout is supported. More details in proxy_link_negotiate_*
+ * functions. */
+ union {
+ struct {
+ /* Version of the negotiation structure. */
+ uint16_t version;
+
+ /* Minimum version that the peer needs to support to
+ * proceed. */
+ uint16_t min_version;
+ } legacy;
+ struct {
+ /* Version of the negotiation structure. */
+ uint8_t version;
+
+ /* Minimum version that the peer needs to support to
+ * proceed. */
+ uint8_t min_version;
+
+ /* Total number of operations supported. */
+ uint16_t num_ops;
+ };
+ };
+
+ /* Total number of callbacks supported. */
+ uint8_t num_cbks;
+
+ /* Flags of the v0 structure. */
+ uint8_t flags;
} proxy_link_negotiate_v0_t;
typedef struct _proxy_link_negotiate_v1 {
sizeof(proxy_link_negotiate_v##_ver##_t))
#define NEG_VERSION_SIZE(_ver) NEG_VERSION_SIZE_1(_ver)
-#define proxy_link_negotiate_init_v0(_neg, _ver, _min) \
+#define proxy_link_negotiate_init_v0(_neg, _ver, _min, _ops, _cbks) \
do { \
(_neg)->v0.size = NEG_VERSION_SIZE(_ver); \
(_neg)->v0.version = (_ver); \
(_neg)->v0.min_version = (_min); \
- (_neg)->v0.flags = 0; \
+ (_neg)->v0.num_ops = (_ops); \
+ (_neg)->v0.num_cbks = (_cbks); \
+ (_neg)->v0.flags = PROXY_NEG_V0_OPS; \
} while (0)
+#define proxy_op_supported(_neg, _op) ((_neg)->v0.num_ops > (_op))
+#define proxy_cbk_supported(_neg, _cbk) ((_neg)->v0.num_cbks > (_cbk))
+
/* NEG_VERSION: Add new arguments and initialize the link->neg.vX with them. */
static inline void proxy_link_negotiate_init(proxy_link_negotiate_t *neg,
uint32_t min_version,
uint32_t supported,
uint32_t required,
uint32_t enabled,
- uint32_t protocol)
+ uint32_t protocol,
+ uint32_t num_ops,
+ uint32_t num_cbks)
{
proxy_link_negotiate_init_v0(neg, PROXY_LINK_NEGOTIATE_VERSION,
- min_version);
+ min_version, num_ops, num_cbks);
neg->v1.supported = supported;
neg->v1.required = required;