summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2019-09-04 20:06:11 +0200
committerSimon Rettberg2019-09-04 20:06:11 +0200
commit543877c7fc17c0a881d6a85c76dfc17f8def7dff (patch)
tree03fbbf1c23a7577a3b9fdf2b5dc0fda3775d8a04
parent[SERVER] Fix altservers_getListForClient() (diff)
downloaddnbd3-543877c7fc17c0a881d6a85c76dfc17f8def7dff.tar.gz
dnbd3-543877c7fc17c0a881d6a85c76dfc17f8def7dff.tar.xz
dnbd3-543877c7fc17c0a881d6a85c76dfc17f8def7dff.zip
[SERVER] Support limiting alt-servers to specific namespace
Not really namespace but simple string matching for the image path. Path is matched from start with no support for glob or regex, so usually you want to have a trailing '/' to limit to certain directories.
-rw-r--r--src/server/altservers.c51
-rw-r--r--src/server/altservers.h4
-rw-r--r--src/server/globals.h8
-rw-r--r--src/server/image.c2
-rw-r--r--src/server/net.c2
5 files changed, 49 insertions, 18 deletions
diff --git a/src/server/altservers.c b/src/server/altservers.c
index 952af4f..943345c 100644
--- a/src/server/altservers.c
+++ b/src/server/altservers.c
@@ -23,7 +23,7 @@ static atomic_int numAltServers = 0;
static pthread_mutex_t altServersLock;
static void *altservers_runCheck(void *data);
-static int altservers_getListForUplink(dnbd3_uplink_t *uplink, int *servers, int size, int current);
+static int altservers_getListForUplink(dnbd3_uplink_t *uplink, const char *image, int *servers, int size, int current);
static void altservers_findUplinkInternal(dnbd3_uplink_t *uplink);
static uint32_t altservers_updateRtt(dnbd3_uplink_t *uplink, int index, uint32_t rtt);
static void altservers_imageFailed(dnbd3_uplink_t *uplink, int server);
@@ -86,6 +86,13 @@ static int addAltFromIni(void *countptr, const char* section, const char* key, c
}
} else if ( strcmp( key, "comment" ) == 0 ) {
snprintf( altServers[index].comment, COMMENT_LENGTH, "%s", value );
+ } else if ( strcmp( key, "namespace" ) == 0 ) {
+ dnbd3_ns_t *elem = malloc( sizeof(*elem) );
+ elem->name = strdup( value );
+ elem->len = strlen( value );
+ do {
+ elem->next = altServers[index].nameSpaces;
+ } while ( !atomic_compare_exchange_weak( &altServers[index].nameSpaces, &elem->next, elem ) );
} else {
logadd( LOG_DEBUG1, "Unknown key in alt-servers section: '%s'", key );
}
@@ -139,6 +146,7 @@ bool altservers_add(dnbd3_host_t *host, const char *comment, const int isPrivate
altServers[freeSlot].host = *host;
altServers[freeSlot].isPrivate = isPrivate;
altServers[freeSlot].isClientOnly = isClientOnly;
+ altServers[freeSlot].nameSpaces = NULL;
if ( comment != NULL ) snprintf( altServers[freeSlot].comment, COMMENT_LENGTH, "%s", comment );
mutex_unlock( &altServersLock );
*index = freeSlot;
@@ -171,15 +179,28 @@ void altservers_findUplinkAsync(dnbd3_uplink_t *uplink)
}
}
+static bool isImageAllowed(dnbd3_alt_server_t *alt, const char *image)
+{
+ if ( alt->nameSpaces == NULL )
+ return true;
+ for ( dnbd3_ns_t *it = alt->nameSpaces; it != NULL; it = it->next ) {
+ if ( strncmp( it->name, image, it->len ) == 0 )
+ return true;
+ }
+ return false;
+}
+
/**
* Get <size> known (working) alt servers, ordered by network closeness
* (by finding the smallest possible subnet)
* Private servers are excluded, so this is what you want to call to
* get a list of servers you can tell a client about
*/
-int altservers_getListForClient(dnbd3_host_t *host, dnbd3_server_entry_t *output, int size)
+int altservers_getListForClient(dnbd3_client_t *client, dnbd3_server_entry_t *output, int size)
{
- if ( host == NULL || host->type == 0 || numAltServers == 0 || output == NULL || size <= 0 ) return 0;
+ dnbd3_host_t *host = &client->host;
+ if ( host->type == 0 || numAltServers == 0 || output == NULL || size <= 0 )
+ return 0;
int i, j;
int count = 0;
uint16_t scores[SERVER_MAX_ALTS] = { 0 };
@@ -188,11 +209,9 @@ int altservers_getListForClient(dnbd3_host_t *host, dnbd3_server_entry_t *output
for ( i = 0; i < numAltServers; ++i ) {
if ( altServers[i].host.type == 0 || altServers[i].isPrivate )
continue; // Slot is empty or uplink is for replication only
- if ( host->type == altServers[i].host.type ) {
- scores[i] = (uint16_t)( 10 + altservers_netCloseness( host, &altServers[i].host ) );
- } else {
- scores[i] = 1; // Wrong address family
- }
+ if ( !isImageAllowed( &altServers[i], client->image->name ) )
+ continue;
+ scores[i] = (uint16_t)( 10 + altservers_netCloseness( host, &altServers[i].host ) );
}
while ( count < size ) {
i = -1;
@@ -244,10 +263,10 @@ static bool isUsableForUplink( dnbd3_uplink_t *uplink, int server, ticks *now )
return fails < SERVER_BAD_UPLINK_MIN || ( rand() % fails ) < SERVER_BAD_UPLINK_MIN;
}
-int altservers_getHostListForReplication(dnbd3_host_t *servers, int size)
+int altservers_getHostListForReplication(const char *image, dnbd3_host_t *servers, int size)
{
int idx[size];
- int num = altservers_getListForUplink( NULL, idx, size, -1 );
+ int num = altservers_getListForUplink( NULL, image, idx, size, -1 );
for ( int i = 0; i < num; ++i ) {
servers[i] = altServers[i].host;
}
@@ -261,7 +280,7 @@ int altservers_getHostListForReplication(dnbd3_host_t *servers, int size)
* it includes private servers and ignores any "client only" servers
* @param current index of server for current connection, or -1 in panic mode
*/
-static int altservers_getListForUplink(dnbd3_uplink_t *uplink, int *servers, int size, int current)
+static int altservers_getListForUplink(dnbd3_uplink_t *uplink, const char *image, int *servers, int size, int current)
{
if ( size <= 0 )
return 0;
@@ -272,7 +291,9 @@ static int altservers_getListForUplink(dnbd3_uplink_t *uplink, int *servers, int
if ( numAltServers <= size ) {
for ( int i = 0; i < numAltServers; ++i ) {
if ( current == -1 || i == current || isUsableForUplink( uplink, i, &now ) ) {
- servers[count++] = i;
+ if ( isImageAllowed( &altServers[i], image ) ) {
+ servers[count++] = i;
+ }
}
}
} else {
@@ -286,7 +307,9 @@ static int altservers_getListForUplink(dnbd3_uplink_t *uplink, int *servers, int
int idx = rand() % numAltServers;
if ( state[idx] != 0 )
continue;
- if ( isUsableForUplink( uplink, idx, &now ) ) {
+ if ( !isImageAllowed( &altServers[idx], image ) ) {
+ state[idx] = 2; // Mark as used without adding, so it will be ignored in panic loop
+ } else if ( isUsableForUplink( uplink, idx, &now ) ) {
servers[count++] = idx;
state[idx] = 2; // Used
} else {
@@ -469,7 +492,7 @@ static void altservers_findUplinkInternal(dnbd3_uplink_t *uplink)
current = uplink->current.index; // Current server index (or last one in panic mode)
mutex_unlock( &uplink->rttLock );
// First, get 4 alt servers
- numAlts = altservers_getListForUplink( uplink, servers, ALTS, panic ? -1 : current );
+ numAlts = altservers_getListForUplink( uplink, uplink->image->name, servers, ALTS, panic ? -1 : current );
// If we're already connected and only got one server anyways, there isn't much to do
if ( numAlts == 0 || ( numAlts == 1 && !panic ) ) {
uplink->rttTestResult = RTT_DONTCHANGE;
diff --git a/src/server/altservers.h b/src/server/altservers.h
index 1e1f119..8e29aaa 100644
--- a/src/server/altservers.h
+++ b/src/server/altservers.h
@@ -15,9 +15,9 @@ void altservers_findUplinkAsync(dnbd3_uplink_t *uplink);
void altservers_findUplink(dnbd3_uplink_t *uplink);
-int altservers_getListForClient(dnbd3_host_t *host, dnbd3_server_entry_t *output, int size);
+int altservers_getListForClient(dnbd3_client_t *client, dnbd3_server_entry_t *output, int size);
-int altservers_getHostListForReplication(dnbd3_host_t *servers, int size);
+int altservers_getHostListForReplication(const char *image, dnbd3_host_t *servers, int size);
bool altservers_toString(int server, char *buffer, size_t len);
diff --git a/src/server/globals.h b/src/server/globals.h
index 221af78..ebdc1c7 100644
--- a/src/server/globals.h
+++ b/src/server/globals.h
@@ -31,6 +31,13 @@ typedef struct
uint8_t hopCount; // How many hops this request has already taken across proxies
} dnbd3_queued_request_t;
+typedef struct _ns
+{
+ struct _ns *next;
+ char *name;
+ size_t len;
+} dnbd3_ns_t;
+
typedef struct
{
int fails; // Hard fail: Connection failed
@@ -41,6 +48,7 @@ typedef struct
ticks lastFail; // Last hard fail
dnbd3_host_t host;
char comment[COMMENT_LENGTH];
+ _Atomic(dnbd3_ns_t *) nameSpaces; // Linked list of name spaces
} dnbd3_alt_server_t;
typedef struct
diff --git a/src/server/image.c b/src/server/image.c
index bdb910d..86e6b87 100644
--- a/src/server/image.c
+++ b/src/server/image.c
@@ -1204,7 +1204,7 @@ static dnbd3_image_t *loadImageProxy(char * const name, const uint16_t revision,
dnbd3_host_t servers[REP_NUM_SRV];
int uplinkSock = -1;
dnbd3_host_t uplinkServer;
- const int count = altservers_getHostListForReplication( servers, REP_NUM_SRV );
+ const int count = altservers_getHostListForReplication( name, servers, REP_NUM_SRV );
uint16_t remoteProtocolVersion;
uint16_t remoteRid = revision;
uint64_t remoteImageSize;
diff --git a/src/server/net.c b/src/server/net.c
index 00c9a8d..aba4e7d 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -477,7 +477,7 @@ void* net_handleNewConnection(void *clientPtr)
case CMD_GET_SERVERS:
// Build list of known working alt servers
- num = altservers_getListForClient( &client->host, server_list, NUMBER_SERVERS );
+ num = altservers_getListForClient( client, server_list, NUMBER_SERVERS );
reply.cmd = CMD_GET_SERVERS;
reply.size = (uint32_t)( num * sizeof(dnbd3_server_entry_t) );
mutex_lock( &client->sendMutex );