From e0bb119bdc1549d731f371202428c0cb667d3388 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 22 Feb 2010 10:28:26 +0100 Subject: Restrict family lookups Adds a new option that tells resolver which address family to prefer or use exclusively. Fixes: #404 --- src/providers/data_provider_fo.c | 52 +++++++++++++++++++++++++++++++++++++--- src/providers/fail_over.c | 25 ++++++++++++------- src/providers/fail_over.h | 22 ++++++++++++++--- 3 files changed, 84 insertions(+), 15 deletions(-) (limited to 'src/providers') diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c index 7d024048..482f7444 100644 --- a/src/providers/data_provider_fo.c +++ b/src/providers/data_provider_fo.c @@ -53,9 +53,47 @@ struct be_failover_ctx { struct be_svc_data *svcs; }; +static int be_fo_get_options(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, + struct fo_options *opts) +{ + char *str_opt; + int ret; + + /* todo get timeout from configuration */ + opts->retry_timeout = 30; + + ret = confdb_get_string(ctx->cdb, mem_ctx, ctx->conf_path, + CONFDB_DOMAIN_FAMILY_ORDER, + "ipv4_first", &str_opt); + if (ret != EOK) { + return ret; + } + + DEBUG(7, ("Lookup order: %s\n", str_opt)); + + if (strcasecmp(str_opt, "ipv4_first") == 0) { + opts->family_order = IPV4_FIRST; + } else if (strcasecmp(str_opt, "ipv4_only") == 0) { + opts->family_order = IPV4_ONLY; + } else if (strcasecmp(str_opt, "ipv6_first") == 0) { + opts->family_order = IPV6_FIRST; + } else if (strcasecmp(str_opt, "ipv6_only") == 0) { + opts->family_order = IPV6_ONLY; + } else { + DEBUG(1, ("Unknown value for option %s: %s\n", + CONFDB_DOMAIN_FAMILY_ORDER, str_opt)); + talloc_free(str_opt); + return EINVAL; + } + + talloc_free(str_opt); + return EOK; +} + int be_init_failover(struct be_ctx *ctx) { int ret; + struct fo_options fopts; if (ctx->be_fo != NULL) { return EOK; @@ -72,8 +110,13 @@ int be_init_failover(struct be_ctx *ctx) return ret; } - /* todo get timeout from configuration */ - ctx->be_fo->fo_ctx = fo_context_init(ctx->be_fo, 30); + ret = be_fo_get_options(ctx->be_fo, ctx, &fopts); + if (ret != EOK) { + talloc_zfree(ctx->be_fo); + return ret; + } + + ctx->be_fo->fo_ctx = fo_context_init(ctx->be_fo, &fopts); if (!ctx->be_fo->fo_ctx) { talloc_zfree(ctx->be_fo); return ENOMEM; @@ -250,7 +293,9 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx, state->attempts = 0; subreq = fo_resolve_service_send(state, ev, - ctx->be_fo->resolv, svc->fo_service); + ctx->be_fo->resolv, + ctx->be_fo->fo_ctx, + svc->fo_service); if (!subreq) { talloc_zfree(req); return NULL; @@ -305,6 +350,7 @@ static void be_resolve_server_done(struct tevent_req *subreq) DEBUG(6, ("Trying with the next one!\n")); subreq = fo_resolve_service_send(state, state->ev, state->ctx->be_fo->resolv, + state->ctx->be_fo->fo_ctx, state->svc->fo_service); if (!subreq) { tevent_req_error(req, ENOMEM); diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c index 7560b89e..54ad0329 100644 --- a/src/providers/fail_over.c +++ b/src/providers/fail_over.c @@ -45,8 +45,7 @@ struct fo_ctx { struct fo_service *service_list; struct server_common *server_common_list; - /* Settings. */ - time_t retry_timeout; + struct fo_options *opts; }; struct fo_service { @@ -99,7 +98,7 @@ struct status { }; struct fo_ctx * -fo_context_init(TALLOC_CTX *mem_ctx, time_t retry_timeout) +fo_context_init(TALLOC_CTX *mem_ctx, struct fo_options *opts) { struct fo_ctx *ctx; @@ -108,11 +107,17 @@ fo_context_init(TALLOC_CTX *mem_ctx, time_t retry_timeout) DEBUG(1, ("No memory\n")); return NULL; } + ctx->opts = talloc_zero(ctx, struct fo_options); + if (ctx->opts == NULL) { + DEBUG(1, ("No memory\n")); + return NULL; + } - ctx->retry_timeout = retry_timeout; + ctx->opts->retry_timeout = opts->retry_timeout; + ctx->opts->family_order = opts->family_order; DEBUG(3, ("Created new fail over context, retry timeout is %d\n", - retry_timeout)); + ctx->opts->retry_timeout)); return ctx; } @@ -166,7 +171,7 @@ get_server_status(struct fo_server *server) DEBUG(7, ("Status of server '%s' is '%s'\n", SERVER_NAME(server), str_server_status(server->common->server_status))); - timeout = server->service->ctx->retry_timeout; + timeout = server->service->ctx->opts->retry_timeout; if (timeout != 0 && server->common->server_status == SERVER_NOT_WORKING) { gettimeofday(&tv, NULL); if (STATUS_DIFF(server->common, tv) > timeout) { @@ -193,7 +198,7 @@ get_port_status(struct fo_server *server) DEBUG(7, ("Port status of port %d for server '%s' is '%s'\n", server->port, SERVER_NAME(server), str_port_status(server->port_status))); - timeout = server->service->ctx->retry_timeout; + timeout = server->service->ctx->opts->retry_timeout; if (timeout != 0 && server->port_status == PORT_NOT_WORKING) { gettimeofday(&tv, NULL); if (STATUS_DIFF(server, tv) > timeout) { @@ -467,7 +472,8 @@ static void fo_resolve_service_done(struct tevent_req *subreq); struct tevent_req * fo_resolve_service_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct resolv_ctx *resolv, struct fo_service *service) + struct resolv_ctx *resolv, struct fo_ctx *ctx, + struct fo_service *service) { int ret; struct fo_server *server; @@ -498,7 +504,8 @@ fo_resolve_service_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, switch (get_server_status(server)) { case SERVER_NAME_NOT_RESOLVED: /* Request name resolution. */ subreq = resolv_gethostbyname_send(server->common, ev, resolv, - server->common->name); + server->common->name, + ctx->opts->family_order); if (subreq == NULL) { ret = ENOMEM; goto done; diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h index f1184832..ffcd0687 100644 --- a/src/providers/fail_over.h +++ b/src/providers/fail_over.h @@ -28,9 +28,10 @@ #include #include +#include "resolv/async_resolv.h" + /* Some forward declarations that don't have to do anything with fail over. */ struct hostent; -struct resolv_ctx; struct tevent_context; struct tevent_req; @@ -53,12 +54,26 @@ struct fo_service; struct fo_server; /* - * Create a new fail over context. The 'retry_timeout' argument specifies the + * Failover settings. + * + * The 'retry_timeout' member specifies the * duration in seconds of how long a server or port will be considered * non-working after being marked as such. + * + * The family_order member specifies the order of address families to + * try when looking up the service. + */ +struct fo_options { + time_t retry_timeout; + enum restrict_family family_order; +}; + +/* + * Create a new fail over context based on options passed in the + * opts parameter */ struct fo_ctx *fo_context_init(TALLOC_CTX *mem_ctx, - time_t retry_timeout); + struct fo_options *opts); /* * Create a new service structure for 'ctx', saving it to the location pointed @@ -94,6 +109,7 @@ int fo_add_server(struct fo_service *service, struct tevent_req *fo_resolve_service_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct resolv_ctx *resolv, + struct fo_ctx *ctx, struct fo_service *service); int fo_resolve_service_recv(struct tevent_req *req, -- cgit