diff --git a/tempesta_fw/Makefile b/tempesta_fw/Makefile index 6d20d13efc..098a971f7d 100644 --- a/tempesta_fw/Makefile +++ b/tempesta_fw/Makefile @@ -50,9 +50,9 @@ tempesta_fw-objs = \ sock_srv.o \ ss_skb.o \ stress.o \ - tfw_tfwcfg.o \ str.o \ tls.o \ + vhost.o \ work_queue.o obj-m += log/ classifier/ stress/ sched/ t/ diff --git a/tempesta_fw/cache.c b/tempesta_fw/cache.c index c9d88add13..ccb0355972 100644 --- a/tempesta_fw/cache.c +++ b/tempesta_fw/cache.c @@ -30,7 +30,7 @@ #include "tdb.h" #include "tempesta_fw.h" -#include "tfw_tfwcfg.h" +#include "vhost.h" #include "cache.h" #include "http_msg.h" #include "procfs.h" @@ -192,24 +192,40 @@ tfw_cache_msg_cacheable(TfwHttpReq *req) } /* - * Match the given request against strings specified in "location", - * "cache_bypass", and "cache_fulfil" directives and according to - * match operators specified in the directives. - * - * Return the constant that identifies the action on a request. - * Currently the actions are "bypass", "fulfill", or "default". + * Find caching policy in specific vhost and location. */ -tfw_stmt_t -tfw_cache_action(TfwHttpReq *req) +static int +tfw_cache_policy(TfwVhost *vhost, TfwLocation *loc, TfwStr *arg) { - TfwCfgLocation *loc; - TfwCfgCacheMatch *cam; - - loc = tfw_location_match(&req->uri_path); - cam = tfw_camatch_match(loc, &req->uri_path); - if (cam) - return cam->stmt; - return TFW_D_CACHE_DEFAULT; + TfwCaPolicy *capo; + + /* Search locations in current vhost. */ + if (loc && loc->capo_sz) { + if ((capo = tfw_capolicy_match(loc, arg))) + return capo->cmd; + } + + /* + * Search default policies in current vhost. + * If there's none, then search global default policies. + */ + loc = vhost->loc_dflt; + if (loc && loc->capo_sz) { + if ((capo = tfw_capolicy_match(loc, arg))) + return capo->cmd; + } else { + TfwVhost *vhost_dflt = tfw_vhost_get_default(); + if (vhost == vhost_dflt) + return TFW_D_CACHE_BYPASS; + + loc = vhost_dflt->loc_dflt; + if (loc && loc->capo_sz) { + if ((capo = tfw_capolicy_match(loc, arg))) + return capo->cmd; + } + } + + return TFW_D_CACHE_BYPASS; } /* @@ -221,26 +237,25 @@ tfw_cache_action(TfwHttpReq *req) * the resulting decision. */ static bool -tfw_cache_employ(TfwHttpReq *req, TfwHttpResp *resp) +tfw_cache_employ_req(TfwHttpReq *req) { - /* - * Process requests according to "location", "cache_bypass", - * and "cache_fulfill" directives. - */ - if (!resp) { - tfw_stmt_t stmt = tfw_cache_action(req); - if ((stmt == TFW_D_CACHE_DEFAULT) - || (stmt == TFW_D_CACHE_BYPASS)) - { - req->cache_ctl.flags |= TFW_HTTP_CC_NO_STORE; - return false; - } - /* cache_fulfill - work as usual in cache mode. */ - BUG_ON(stmt != TFW_D_CACHE_FULFILL); - } else { - if (req->cache_ctl.flags & TFW_HTTP_CC_NO_STORE) - return false; + int cmd = tfw_cache_policy(req->vhost, req->location, &req->uri_path); + + if (cmd == TFW_D_CACHE_BYPASS) { + req->cache_ctl.flags |= TFW_HTTP_CC_CACHE_BYPASS; + return false; } + /* cache_fulfill - work as usual in cache mode. */ + BUG_ON(cmd != TFW_D_CACHE_FULFILL); + + return true; +} + +static bool +tfw_cache_employ_resp(TfwHttpReq *req, TfwHttpResp *resp) +{ + if (req->cache_ctl.flags & TFW_HTTP_CC_CACHE_BYPASS) + return false; return true; } @@ -626,7 +641,7 @@ tfw_cache_add(TfwHttpResp *resp, TfwHttpReq *req) if (!cache_cfg.cache || !tfw_cache_msg_cacheable(req)) return true; - if (!tfw_cache_employ(req, resp)) + if (!tfw_cache_employ_resp(req, resp)) return true; key = tfw_http_req_key_calc(req); @@ -668,7 +683,7 @@ tfw_cache_process(TfwHttpReq *req, TfwHttpResp *resp, if (!cache_cfg.cache || !tfw_cache_msg_cacheable(req)) goto dont_cache; - if (!tfw_cache_employ(req, resp)) + if (!resp && !tfw_cache_employ_req(req)) goto dont_cache; cw.req = req; diff --git a/tempesta_fw/http.c b/tempesta_fw/http.c index 1102746c81..8335a0a944 100644 --- a/tempesta_fw/http.c +++ b/tempesta_fw/http.c @@ -723,6 +723,14 @@ tfw_http_req_cache_cb(TfwHttpReq *req, TfwHttpResp *resp) tfw_srv_conn_release(srv_conn); } +static int +tfw_http_req_set_context(TfwHttpReq *req) +{ + req->vhost = tfw_vhost_match(&req->uri_path); + req->location = tfw_location_match(req->vhost, &req->uri_path); + return (!req->location); +} + /** * @return zero on success and negative value otherwise. * TODO enter the function depending on current GFSM state. @@ -811,6 +819,10 @@ tfw_http_req_process(TfwConnection *conn, struct sk_buff *skb, unsigned int off) return TFW_BLOCK; } + /* Assign the right Vhost for this request. */ + if (tfw_http_req_set_context((TfwHttpReq *)hmreq)) + return TFW_BLOCK; + /* * In HTTP 0.9 the server always closes the connection * after sending the response. @@ -868,6 +880,7 @@ tfw_http_req_process(TfwConnection *conn, struct sk_buff *skb, unsigned int off) return TFW_BLOCK; } } + /* * Complete HTTP message has been collected and processed * with success. Mark the message as complete in @conn as diff --git a/tempesta_fw/http.h b/tempesta_fw/http.h index 1419a306b6..ae8ec46089 100644 --- a/tempesta_fw/http.h +++ b/tempesta_fw/http.h @@ -22,6 +22,7 @@ #define __TFW_HTTP_H__ #include "connection.h" +#include "vhost.h" #include "gfsm.h" #include "msg.h" #include "str.h" @@ -103,6 +104,7 @@ enum { #define TFW_HTTP_CC_PROXY_REV 0x040 #define TFW_HTTP_CC_PUBLIC 0x080 #define TFW_HTTP_CC_PRIVATE 0x100 +#define TFW_HTTP_CC_CACHE_BYPASS 0x100000 typedef struct { unsigned int flags; unsigned int max_age; @@ -255,6 +257,8 @@ typedef struct { */ typedef struct { TFW_HTTP_MSG_COMMON; + TfwVhost *vhost; + TfwLocation *location; TfwStr userinfo; TfwStr host; TfwStr uri_path; diff --git a/tempesta_fw/http_match.h b/tempesta_fw/http_match.h index eae0f1b988..527906d121 100644 --- a/tempesta_fw/http_match.h +++ b/tempesta_fw/http_match.h @@ -47,6 +47,8 @@ typedef enum { _TFW_HTTP_MATCH_O_COUNT } tfw_http_match_op_t; +typedef tfw_http_match_op_t tfw_match_t; + typedef enum { TFW_HTTP_MATCH_A_NA = 0, TFW_HTTP_MATCH_A_WILDCARD, diff --git a/tempesta_fw/main.c b/tempesta_fw/main.c index 0f2bc6d0ac..536f05d073 100644 --- a/tempesta_fw/main.c +++ b/tempesta_fw/main.c @@ -76,7 +76,7 @@ tfw_init(void) DO_INIT(cfg_if); DO_INIT(procfs); - DO_INIT(tfwcfg); + DO_INIT(vhost); DO_INIT(classifier); @@ -91,7 +91,7 @@ tfw_init(void) DO_INIT(sock_srv); DO_INIT(sock_clnt); - DO_CFG_REG(tfwcfg); + DO_CFG_REG(vhost); DO_CFG_REG(filter); DO_CFG_REG(cache); DO_CFG_REG(http_sticky); diff --git a/tempesta_fw/t/unit/test.c b/tempesta_fw/t/unit/test.c index 4856aa385d..9ae6466167 100644 --- a/tempesta_fw/t/unit/test.c +++ b/tempesta_fw/t/unit/test.c @@ -22,7 +22,7 @@ #include #include "test.h" -#include "tfw_tfwcfg.c" +#include "vhost.c" int test_fail_counter; test_fixture_fn_t test_setup_fn; diff --git a/tempesta_fw/tfw_tfwcfg.c b/tempesta_fw/tfw_tfwcfg.c deleted file mode 100644 index 6c79d85c2b..0000000000 --- a/tempesta_fw/tfw_tfwcfg.c +++ /dev/null @@ -1,676 +0,0 @@ -/** - * Tempesta FW - * - * Copyright (C) 2016 Tempesta Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, - * or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#include "tempesta_fw.h" -#include "tfw_tfwcfg.h" -#include "str.h" - -/* - * Helper function that converts a constant value (enum) to a string - * that it corresponds to. Also there's conversion from a string to - * a corresponding constant. Currenty that's done via TfwCfgEnum and - * tfw_cfg_map_enum() function. - */ -static const char * -tfw_enum_string(const char * const * enum_string, int enum_max, int enum_val) -{ - if ((enum_val < 0) || (enum_val >= enum_max)) - return enum_string[enum_max]; - if (enum_string[enum_val]) - return enum_string[enum_val]; - return enum_string[enum_max]; -} - -/* Mappings and functions for configuration directives (statements). */ -static const TfwCfgEnum const __read_mostly __tfwcfg_stmt_enum[] = { - { "cache_bypass", TFW_D_CACHE_BYPASS }, - { "cache_fulfill", TFW_D_CACHE_FULFILL }, - {} -}; -static const char * const __read_mostly __tfwcfg_enum_stmt[] = { - [0 ... _TFW_D_COUNT] = NULL, - [TFW_D_CACHE_BYPASS] = "cache_bypass", - [TFW_D_CACHE_FULFILL] = "cache_fulfill", - [_TFW_D_COUNT] = "UNKNOWN", -}; -const char * -tfw_stmt_string(tfw_stmt_t stmt) -{ - return tfw_enum_string(__tfwcfg_enum_stmt, _TFW_D_COUNT, stmt); -} - -/* Mappings for match operators. */ -static const TfwCfgEnum const __read_mostly tfwcfg_match_enum[] = { - { "*", TFW_HTTP_MATCH_O_WILDCARD }, - { "eq", TFW_HTTP_MATCH_O_EQ }, - { "prefix", TFW_HTTP_MATCH_O_PREFIX }, - { "suffix", TFW_HTTP_MATCH_O_SUFFIX }, - {} -}; - -/* - * All 'location' directives are put into a fixed size array. - * Duplicate directives are not allowed. - */ -#define TFW_LOCATION_ARRAY_SZ (64) - -static TfwCfgLocation *tfwcfg_location; -static unsigned int tfwcfg_location_sz; /* Current size. */ -static unsigned int tfwcfg_location_max; /* Maximum size. */ - -/* - * All cache action directives are put into a fixed size array. - * The directives are deduplicated when put into the array. - * Individual directives are linked to from lists of cache action - * directives for specific location sections. - */ -#define TFW_CAMATCH_ARRAY_SZ (64) - -static TfwCfgCacheMatch *tfwcfg_camatch; -static unsigned int tfwcfg_camatch_sz; /* Current size. */ -static unsigned int tfwcfg_camatch_max; /* Maximum size. */ - -/* - * Default location is a wildcard location. It matches any URI. - * It may (or may not) contain a set of cache matching directives. - */ -static TfwCfgCacheMatch *tfwcfg_camatch_dflt[TFW_CAMATCH_ARRAY_SZ]; - -static TfwCfgLocation tfwcfg_location_dflt = { - .op = TFW_HTTP_MATCH_O_WILDCARD, - .arg = "*", - .len = 1, - .cam = tfwcfg_camatch_dflt, - .cam_sz = 0, - .cam_max = TFW_CAMATCH_ARRAY_SZ -}; - -/* - * Matching functions for match operators. A TfwStr{} is compared - * with a plain C string according to a specified match operator. - * The functions are generic. - */ -static bool -__tfwcfg_match_wildcard(tfw_match_t op, const char *cstr, int len, TfwStr *arg) -{ - return ((op == TFW_HTTP_MATCH_O_WILDCARD) - && (len == 1) && (*cstr == '*')); -} - -static bool -__tfwcfg_match_suffix(tfw_match_t op, const char *cstr, int len, TfwStr *arg) -{ - tfw_str_eq_flags_t flags = TFW_STR_EQ_DEFAULT | TFW_STR_EQ_CASEI; - return tfw_str_eq_cstr_off(arg, arg->len - len, cstr, len, flags); -} - -static bool -__tfwcfg_match_eq(tfw_match_t op, const char *cstr, int len, TfwStr *arg) -{ - tfw_str_eq_flags_t flags = TFW_STR_EQ_DEFAULT | TFW_STR_EQ_CASEI; - return tfw_str_eq_cstr(arg, cstr, len, flags); -} - -static bool -__tfwcfg_match_prefix(tfw_match_t op, const char *cstr, int len, TfwStr *arg) -{ - tfw_str_eq_flags_t flags = TFW_STR_EQ_PREFIX | TFW_STR_EQ_CASEI; - return tfw_str_eq_cstr(arg, cstr, len, flags); -} - -typedef bool (*__tfwcfg_match_fn)(tfw_match_t, const char *, int, TfwStr *); - -static const __tfwcfg_match_fn const __read_mostly __tfwcfg_match_fn_tbl[] = { - [0 ... _TFW_HTTP_MATCH_O_COUNT] = NULL, - [TFW_HTTP_MATCH_O_WILDCARD] = __tfwcfg_match_wildcard, - [TFW_HTTP_MATCH_O_EQ] = __tfwcfg_match_eq, - [TFW_HTTP_MATCH_O_PREFIX] = __tfwcfg_match_prefix, - [TFW_HTTP_MATCH_O_SUFFIX] = __tfwcfg_match_suffix, -}; - -/* - * Find a matching cache action directive. Strings are compared - * according to the match operator in the directive. A pointer - * to the matching TfwCfgCacheMatch structure is returned if - * the match is found. Null is returned if there's no match. - */ -static bool -__tfw_camatch_match(TfwCfgCacheMatch *cam, TfwStr *arg) -{ - __tfwcfg_match_fn match_fn; - - match_fn = __tfwcfg_match_fn_tbl[cam->op]; - BUG_ON(!match_fn); - - return match_fn(cam->op, cam->arg, cam->len, arg); -} - -TfwCfgCacheMatch * -tfw_camatch_match(TfwCfgLocation *loc, TfwStr *arg) -{ - int i; - - if (!loc || !loc->cam_sz) - return NULL; - - for (i = 0; i < loc->cam_sz; ++i) { - TfwCfgCacheMatch *cam = loc->cam[i]; - if (__tfw_camatch_match(cam, arg)) - return cam; - } - return NULL; -} - -/* - * Find a maching location directive. Strings are compared according - * to the match operator in the directive. A pointer to the matching - * TfwCfgLocation structure is returned if the match is found. - * A pointer to the default location structure is returned if there's - * no match. - */ -static bool -__tfw_location_match(TfwCfgLocation *loc, TfwStr *arg) -{ - __tfwcfg_match_fn match_fn; - - match_fn = __tfwcfg_match_fn_tbl[loc->op]; - BUG_ON(!match_fn); - - return match_fn(loc->op, loc->arg, loc->len, arg); -} - -TfwCfgLocation * -tfw_location_match(TfwStr *arg) -{ - int i; - - for (i = 0; i < tfwcfg_location_sz; ++i) { - TfwCfgLocation *loc = &tfwcfg_location[i]; - if (__tfw_location_match(loc, arg)) - return loc; - } - if (tfwcfg_location_dflt.cam_sz) - return &tfwcfg_location_dflt; - - return NULL; -} - -/* - * Configuration processing. - */ - -/* - * Pointer to the current location structure. - * The pointer is shared among several functions below. - */ -static TfwCfgLocation *tfwcfg_this_location; - -/* - * Find a cache action directive entry. The entry is looked up - * in the array that holds all cache action directives from all - * location sections. - */ -static TfwCfgCacheMatch * -tfwcfg_camatch_lookup(tfw_stmt_t stmt, tfw_match_t op, const char *arg, int len) -{ - int i; - - for (i = 0; i < tfwcfg_camatch_sz; ++i) { - TfwCfgCacheMatch *cam = &tfwcfg_camatch[i]; - if ((cam->stmt == stmt) && (cam->op == op) && (cam->len == len) - && !strncasecmp(cam->arg, arg, len)) - return cam; - } - - return NULL; -} - -/* - * Create and initialize a new cache action entry. The entry is placed - * in the array for all cache action entries from all location sections. - */ -static TfwCfgCacheMatch * -tfwcfg_camatch_new(tfw_stmt_t stmt, tfw_match_t op, const char *arg, int len) -{ - char *argmem; - TfwCfgCacheMatch *cam; - - if (tfwcfg_camatch_sz == tfwcfg_camatch_max) - return NULL; - - if ((argmem = kmalloc(len + 1, GFP_KERNEL)) == NULL) - return NULL; - - cam = &tfwcfg_camatch[tfwcfg_camatch_sz++]; - cam->stmt = stmt; - cam->op = op; - cam->arg = argmem; - cam->len = len; - memcpy((void *)cam->arg, (void *)arg, len + 1); - - return cam; -} - -/* - * Add a new cache action entry to the given location structure. - * The entry is added as a pointer into the array for all cache - * action entries. - */ -static TfwCfgCacheMatch * -tfwcfg_camatch_add(TfwCfgLocation *loc, TfwCfgCacheMatch *cam) -{ - if (loc->cam_sz == loc->cam_max) - return NULL; - loc->cam[loc->cam_sz++] = cam; - return cam; -} - -/* - * Process a cache action directive. The directive is added to the - * current location structure. Duplicate directives are ignored but - * a warning is produced in that case. if a directive lists several - * strings to match, then an identical directive is added for each - * string that is listed. - */ -static int -tfwcfg_handle_camatch(TfwCfgSpec *cs, TfwCfgEntry *ce, tfw_stmt_t stmt) -{ - int i, ret, in_len; - tfw_match_t op; - const char *in_op, *in_arg; - - BUG_ON(!tfwcfg_this_location); - BUG_ON((stmt != TFW_D_CACHE_BYPASS) && (stmt != TFW_D_CACHE_FULFILL)); - - if (ce->attr_n || (ce->val_n < 2)) - return -EINVAL; - - in_op = ce->vals[0]; /* Match operator. */ - - /* Convert the match operator string to the enum value. */ - ret = tfw_cfg_map_enum(tfwcfg_match_enum, in_op, &op); - if (ret) { - TFW_ERR("Unknown match OP: '%s %s'\n", cs->name, in_op); - return -EINVAL; - } - - /* Add each match string in the directive to the array.*/ - for (i = 1; i < ce->val_n; ++i) { - TfwCfgCacheMatch *cam; - - in_arg = ce->vals[i]; - in_len = strlen(in_arg); - - /* Get the cache action entry. */ - cam = tfwcfg_camatch_lookup(stmt, op, in_arg, in_len); - if (cam) { - TFW_WARN("%s: Duplicate entry: '%s %s %s'\n", - cs->name, cs->name, in_op, in_arg); - continue; - } - cam = tfwcfg_camatch_new(stmt, op, in_arg, in_len); - if (!cam) - return -ENOMEM; - /* Link the cache action entry with the location entry. */ - if (!tfwcfg_camatch_add(tfwcfg_this_location, cam)) - return -ENOENT; - } - - return 0; -} - -/* - * The configuration parser has recognized the cache action directive - * already, so there's no need to spend cycles and convert it again - * from the string to the enum value. The functions below are for - * each directive inside the location section, and for each directive - * outside of any location section. - */ -static int -tfwcfg_handle_in_cache_fulfill(TfwCfgSpec *cs, TfwCfgEntry *ce) -{ - return tfwcfg_handle_camatch(cs, ce, TFW_D_CACHE_FULFILL); -} - -static int -tfwcfg_handle_in_cache_bypass(TfwCfgSpec *cs, TfwCfgEntry *ce) -{ - return tfwcfg_handle_camatch(cs, ce, TFW_D_CACHE_BYPASS); -} - -static int -tfwcfg_handle_out_cache_fulfill(TfwCfgSpec *cs, TfwCfgEntry *ce) -{ - if (!tfwcfg_this_location) - tfwcfg_this_location = &tfwcfg_location_dflt; - return tfwcfg_handle_camatch(cs, ce, TFW_D_CACHE_FULFILL); -} - -static int -tfwcfg_handle_out_cache_bypass(TfwCfgSpec *cs, TfwCfgEntry *ce) -{ - if (!tfwcfg_this_location) - tfwcfg_this_location = &tfwcfg_location_dflt; - return tfwcfg_handle_camatch(cs, ce, TFW_D_CACHE_BYPASS); -} - -/* - * Find a location directive entry. The entry is looked up - * in the array that holds all location directives. - */ -static TfwCfgLocation * -tfwcfg_location_lookup(tfw_match_t op, const char *arg, int len) -{ - int i; - - for (i = 0; i < tfwcfg_location_sz; ++i) { - TfwCfgLocation *loc = &tfwcfg_location[i]; - if ((loc->op == op) && (loc->len == len) - && !strncasecmp(loc->arg, arg, len)) - return loc; - } - - return NULL; -} - -/* - * Create and initialize a new entry for a location directive. - * The entry is placed in the array that holds all location directives. - */ -static TfwCfgLocation * -tfwcfg_location_new(tfw_match_t op, const char *arg, int len) -{ - char *argmem; - TfwCfgLocation *loc; - TfwCfgCacheMatch **cam; - size_t size = sizeof(TfwCfgCacheMatch *) * TFW_CAMATCH_ARRAY_SZ; - - if (tfwcfg_location_sz == tfwcfg_location_max) - return NULL; - - if ((argmem = kmalloc(len + 1, GFP_KERNEL)) == NULL) - return NULL; - if ((cam = kmalloc(size, GFP_KERNEL)) == NULL) { - kfree(argmem); - return NULL; - } - - loc = &tfwcfg_location[tfwcfg_location_sz++]; - loc->op = op; - loc->arg = argmem; - loc->len = len; - loc->cam = cam; - loc->cam_sz = 0; - loc->cam_max = TFW_CAMATCH_ARRAY_SZ; - memcpy((void *)loc->arg, (void *)arg, len + 1); - - return loc; -} - -/* - * Process the location directive that opens a section for cache - * action directives in the configuration. - */ -static int -tfwcfg_begin_location(TfwCfgSpec *cs, TfwCfgEntry *ce) -{ - int ret, in_len; - tfw_match_t op; - const char *in_op, *in_arg; - - if (ce->attr_n || (ce->val_n != 2)) - return -EINVAL; - - /* Get the values of the 'location' directive. */ - in_op = ce->vals[0]; /* Match operator. */ - in_arg = ce->vals[1]; /* String for the match operator. */ - in_len = strlen(in_arg); - - /* Convert the match operator string to the enum value. */ - ret = tfw_cfg_map_enum(tfwcfg_match_enum, in_op, &op); - if (ret) { - TFW_ERR("%s: Unknown match OP: '%s %s %s'\n", - cs->name, cs->name, in_op, in_arg); - return -EINVAL; - } - - /* Make sure the location is not a duplicate. */ - if (tfwcfg_location_lookup(op, in_arg, in_len)) { - TFW_ERR("%s: Duplicate entry: '%s %s %s'\n", - cs->name, cs->name, in_op, in_arg); - return -EINVAL; - } - - /* Add new location and set it to be the current one. */ - tfwcfg_this_location = tfwcfg_location_new(op, in_arg, in_len); - if (tfwcfg_this_location == NULL) { - TFW_ERR("%s: Unable to add new location: '%s %s %s'\n", - cs->name, cs->name, in_op, in_arg); - return -EINVAL; - } - - return 0; -} - -/* - * Close the section for a location directive. - */ -static int -tfwcfg_finish_location(TfwCfgSpec *cs) -{ - BUG_ON(!tfwcfg_this_location); - tfwcfg_this_location = NULL; - return 0; -} - -/* - * Free only the memory that has been allocated while processing - * configuration directives. Make sure the memory is not freed twice. - */ -static void -__tfwcfg_cleanup_locache(void) -{ - int i; - - for (i = 0; i < tfwcfg_location_sz; ++i) { - TfwCfgLocation *loc = &tfwcfg_location[i]; - if (loc->arg) { - kfree(loc->arg); - loc->arg = NULL; - } - if (loc->cam) { - kfree(loc->cam); - loc->cam = NULL; - } - } - for (i = 0; i < tfwcfg_camatch_sz; ++i) { - TfwCfgCacheMatch *cam = &tfwcfg_camatch[i]; - if (cam->arg) { - kfree(cam->arg); - cam->arg = NULL; - } - } -} - -static void -tfwcfg_cleanup_locache(TfwCfgSpec *cs) -{ - __tfwcfg_cleanup_locache(); -} - -static void -tfwcfg_location_print_one(int idx, TfwCfgLocation *loc) -{ - int i; - - printk(KERN_ERR "%s: [%d]: location op [%d] arg [%s] len [%d]" - " cam [%p] cam_sz [%d] cam_max [%d]\n", - __func__, idx, loc->op, loc->arg, loc->len, - loc->cam, loc->cam_sz, loc->cam_max); - - if (!loc->cam) - return; - - for (i = 0; i < loc->cam_sz; ++i) { - TfwCfgCacheMatch *cam = loc->cam[i]; - printk(KERN_ERR " %s: [%d]: cache match stmt [%d]" - " op [%d] arg [%s] len [%d]\n", - __func__, i, cam->stmt, cam->op, - cam->arg, cam->len); - } -} -static void -tfwcfg_location_print_all(void) -{ - int i; - - printk(KERN_ERR "%s: tfwcfg_location_sz [%d] tfwcfg_location_max [%d]\n", - __func__, tfwcfg_location_sz, tfwcfg_location_max); - - for (i = 0; i < tfwcfg_location_sz; ++i) { - TfwCfgLocation *loc = &tfwcfg_location[i]; - tfwcfg_location_print_one(i, loc); - } - - printk(KERN_ERR "%s: default location\n", __func__); - tfwcfg_location_print_one(0, &tfwcfg_location_dflt); -} - -static int -tfwcfg_start(void) -{ -tfwcfg_location_print_all(); - return 0; -} - -static void -tfwcfg_stop(void) -{ - __tfwcfg_cleanup_locache(); -} - -static TfwCfgSpec tfwcfg_location_specs[] = { - { - "cache_bypass", NULL, - tfwcfg_handle_in_cache_bypass, - .allow_none = true, - .allow_repeat = true, - .cleanup = tfwcfg_cleanup_locache - }, - { - "cache_fulfill", NULL, - tfwcfg_handle_in_cache_fulfill, - .allow_none = true, - .allow_repeat = true, - .cleanup = tfwcfg_cleanup_locache - }, - {} -}; - -static TfwCfgSpec tfwcfg_specs[] = { - { - "cache_bypass", NULL, - tfwcfg_handle_out_cache_bypass, - .allow_none = true, - .allow_repeat = true, - .cleanup = tfwcfg_cleanup_locache - }, - { - "cache_fulfill", NULL, - tfwcfg_handle_out_cache_fulfill, - .allow_none = true, - .allow_repeat = true, - .cleanup = tfwcfg_cleanup_locache - }, - { - "location", NULL, - tfw_cfg_handle_children, - tfwcfg_location_specs, - &(TfwCfgSpecChild) { - .begin_hook = tfwcfg_begin_location, - .finish_hook = tfwcfg_finish_location - }, - .allow_none = true, - .allow_repeat = true, - /* .cleanup function in a section with - children causes a BUG_ON in cfg.c. */ - }, - {}, -}; - -TfwCfgMod tfw_tfwcfg_cfg_mod = { - .name = "tfwcfg", - .start = tfwcfg_start, - .stop = tfwcfg_stop, - .specs = tfwcfg_specs, -}; - -int -tfw_tfwcfg_init(void) -{ - int size; - - BUG_ON(tfwcfg_camatch); - BUG_ON(tfwcfg_location); - - /* Array of location directives. */ - size = sizeof(TfwCfgLocation) * TFW_LOCATION_ARRAY_SZ; - tfwcfg_location = kzalloc(size, GFP_KERNEL); - if (!tfwcfg_location) { - TFW_ERR("Unable to allocate memory" - " for location directives: %d bytes\n", size); - return -ENOMEM; - } - tfwcfg_location_sz = 0; - tfwcfg_location_max = TFW_LOCATION_ARRAY_SZ; - - /* Array of cache action directives. */ - size = sizeof(TfwCfgCacheMatch) * TFW_CAMATCH_ARRAY_SZ; - tfwcfg_camatch = kzalloc(size, GFP_KERNEL); - if (!tfwcfg_camatch) { - TFW_ERR("Unable to allocate memory" - " for cache action directives: %d bytes\n", size); - kfree(tfwcfg_location); - tfwcfg_location = NULL; - return -ENOMEM; - } - tfwcfg_camatch_sz = 0; - tfwcfg_camatch_max = TFW_CAMATCH_ARRAY_SZ; - - return 0; -} - -void -tfw_tfwcfg_exit(void) -{ - int i; - - if (tfwcfg_camatch) { - kfree(tfwcfg_camatch); - tfwcfg_camatch = NULL; - } - if (tfwcfg_location) { - for (i = 0; i < tfwcfg_location_sz; ++i) - if (tfwcfg_location[i].cam) - kfree(tfwcfg_location[i].cam); - kfree(tfwcfg_location); - tfwcfg_location = NULL; - } -} - diff --git a/tempesta_fw/tfw_tfwcfg.h b/tempesta_fw/tfw_tfwcfg.h deleted file mode 100644 index aecda6ec1f..0000000000 --- a/tempesta_fw/tfw_tfwcfg.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Tempesta FW - * - * Copyright (C) 2016 Tempesta Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, - * or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#include "str.h" -#include "http_match.h" - -typedef tfw_http_match_op_t tfw_match_t; - -/* - * List of Tempesta configuration directives. - * - * "stmt" (statement) word is used to make - * ithe name of the variable short and concise. - */ -typedef enum { - /* Cache directives. */ - TFW_D_CACHE_BYPASS, - TFW_D_CACHE_FULFILL, - TFW_D_CACHE_DEFAULT, - - _TFW_D_COUNT -} tfw_stmt_t; - -typedef struct { - tfw_stmt_t stmt; - tfw_match_t op; - const char *arg; - unsigned int len; -} TfwCfgCacheMatch; - -typedef struct { - tfw_match_t op; - const char *arg; - unsigned int len; - TfwCfgCacheMatch **cam; - unsigned int cam_sz; - unsigned int cam_max; -} TfwCfgLocation; - - -const char * tfw_stmt_string(tfw_stmt_t stmt); -TfwCfgCacheMatch * tfw_camatch_match(TfwCfgLocation *loc, TfwStr *arg); -TfwCfgLocation * tfw_location_match(TfwStr *arg); diff --git a/tempesta_fw/vhost.c b/tempesta_fw/vhost.c new file mode 100644 index 0000000000..da9afd51fd --- /dev/null +++ b/tempesta_fw/vhost.c @@ -0,0 +1,609 @@ +/** + * Tempesta FW + * + * Copyright (C) 2016 Tempesta Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "tempesta_fw.h" +#include "http_match.h" +#include "vhost.h" +#include "str.h" + +/* Mappings for match operators. */ +static const TfwCfgEnum const __read_mostly tfw_match_enum[] = { + { "*", TFW_HTTP_MATCH_O_WILDCARD }, + { "eq", TFW_HTTP_MATCH_O_EQ }, + { "prefix", TFW_HTTP_MATCH_O_PREFIX }, + { "suffix", TFW_HTTP_MATCH_O_SUFFIX }, + {} +}; + +/* + * All cache policy directives are put into a fixed size array. + * The directives are deduplicated when put into the array. + * Individual directives are linked to from lists of cache policy + * directives for specific location sections. + */ +#define TFW_CAPOLICY_ARRAY_SZ (64) + +static TfwCaPolicy tfw_capolicy[TFW_CAPOLICY_ARRAY_SZ]; +static unsigned int tfw_capolicy_sz = 0; /* Current size. */ + +/* + * All 'location' directives are put into a fixed size array. + * Duplicate directives are not allowed. + */ +#define TFW_LOCATION_ARRAY_SZ (64) + +static TfwLocation tfw_location[TFW_LOCATION_ARRAY_SZ]; +static unsigned int tfw_location_sz = 0; /* Current size. */ + +/* + * Default location is a wildcard location. It matches any URI. + * It may (or may not) contain a set of cache matching directives. + */ +static TfwCaPolicy *tfw_capolicy_dflt[TFW_CAPOLICY_ARRAY_SZ]; + +static TfwLocation tfw_location_dflt = { + .op = TFW_HTTP_MATCH_O_WILDCARD, + .arg = "*", + .len = 1, + .capo = tfw_capolicy_dflt, + .capo_sz = 0, +}; + +/* + * Default vhost is a wildcard vhost. It matches any URI. + * It may (or may not) ontain a set of various directives. + */ +static TfwVhost tfw_vhost_dflt = { + .loc = tfw_location, + .loc_dflt = &tfw_location_dflt, + .loc_dflt_sz = 1 +}; + +/* + * Matching functions for match operators. A TfwStr{} is compared + * with a plain C string according to a specified match operator. + * The functions are generic. + */ +static bool +__tfw_match_wildcard(tfw_match_t op, const char *cstr, int len, TfwStr *arg) +{ + return ((op == TFW_HTTP_MATCH_O_WILDCARD) + && (len == 1) && (*cstr == '*')); +} + +static bool +__tfw_match_suffix(tfw_match_t op, const char *cstr, int len, TfwStr *arg) +{ + tfw_str_eq_flags_t flags = TFW_STR_EQ_DEFAULT | TFW_STR_EQ_CASEI; + return tfw_str_eq_cstr_off(arg, arg->len - len, cstr, len, flags); +} + +static bool +__tfw_match_eq(tfw_match_t op, const char *cstr, int len, TfwStr *arg) +{ + tfw_str_eq_flags_t flags = TFW_STR_EQ_DEFAULT | TFW_STR_EQ_CASEI; + return tfw_str_eq_cstr(arg, cstr, len, flags); +} + +static bool +__tfw_match_prefix(tfw_match_t op, const char *cstr, int len, TfwStr *arg) +{ + tfw_str_eq_flags_t flags = TFW_STR_EQ_PREFIX | TFW_STR_EQ_CASEI; + return tfw_str_eq_cstr(arg, cstr, len, flags); +} + +typedef bool (*__tfw_match_fn)(tfw_match_t, const char *, int, TfwStr *); + +static const __tfw_match_fn const __read_mostly __tfw_match_fn_tbl[] = { + [0 ... _TFW_HTTP_MATCH_O_COUNT] = NULL, + [TFW_HTTP_MATCH_O_WILDCARD] = __tfw_match_wildcard, + [TFW_HTTP_MATCH_O_EQ] = __tfw_match_eq, + [TFW_HTTP_MATCH_O_PREFIX] = __tfw_match_prefix, + [TFW_HTTP_MATCH_O_SUFFIX] = __tfw_match_suffix, +}; + +/* + * Find a matching cache policy directive. Strings are compared + * according to the match operator in the directive. A pointer + * to the matching TfwCaPolicy structure is returned if the + * match is found. Null is returned if there's no match. + */ +static bool +__tfw_capolicy_match_fn(TfwCaPolicy *capo, TfwStr *arg) +{ + __tfw_match_fn match_fn; + + match_fn = __tfw_match_fn_tbl[capo->op]; + BUG_ON(!match_fn); + + return match_fn(capo->op, capo->arg, capo->len, arg); +} + +TfwCaPolicy * +tfw_capolicy_match(TfwLocation *loc, TfwStr *arg) +{ + int i; + + BUG_ON(!loc); + BUG_ON(!arg); + + for (i = 0; i < loc->capo_sz; ++i) { + TfwCaPolicy *capo = loc->capo[i]; + __func__, capo->cmd, capo->op, capo->len, capo->arg); + if (__tfw_capolicy_match_fn(capo, arg)) + return capo; + } + return NULL; +} + +/* + * Find a matching location directive within specified vhost. + * A pointer to the matching TfwLocation structure is returned + * if the match is found. NULL is returned if there's no match. + */ +static bool +__tfw_location_match(TfwLocation *loc, TfwStr *arg) +{ + __tfw_match_fn match_fn; + + match_fn = __tfw_match_fn_tbl[loc->op]; + BUG_ON(!match_fn); + + return match_fn(loc->op, loc->arg, loc->len, arg); +} + +TfwLocation * +tfw_location_match(TfwVhost *vhost, TfwStr *arg) +{ + int i; + + BUG_ON(!vhost); + BUG_ON(!arg); + + for (i = 0; i < vhost->loc_sz; ++i) { + TfwLocation *loc = &vhost->loc[i]; + if (__tfw_location_match(loc, arg)) + return loc; + } + return NULL; +} + +/* + * Find a matching vhost directive. Strings are compared according + * to the match operator in the directive. A pointer to the matching + * TfwVhost structure is returned if the match is found. A pointer + * to the default vhost structure is returned if there's no match. + */ +TfwVhost * +tfw_vhost_get_default(void) +{ + return &tfw_vhost_dflt; +} + +TfwVhost * +tfw_vhost_match(TfwStr *arg) +{ + BUG_ON(!arg); + + /* For now there's just the default vhost. */ + return &tfw_vhost_dflt; +} + +/* + * Configuration processing. + */ + +/* + * Pointer to the current location structure. + * The pointer is shared among several functions below. + */ +static TfwLocation *tfwcfg_this_location; + +/* + * Find a cache policy directive entry. The entry is looked up + * in the array that holds all cache policy directives from all + * location sections. + */ +static TfwCaPolicy * +tfw_capolicy_lookup(const short cmd, const short op, const char *arg, int len) +{ + int i; + + for (i = 0; i < tfw_capolicy_sz; ++i) { + TfwCaPolicy *capo = &tfw_capolicy[i]; + if ((capo->cmd == cmd) && (capo->op == op) && (capo->len == len) + && !strncasecmp(capo->arg, arg, len)) + return capo; + } + + return NULL; +} + +/* + * Create and initialize a new cache policy entry. The entry is placed + * in the array for all cache policy entries from all location sections. + */ +static TfwCaPolicy * +tfw_capolicy_new(const short cmd, const short op, const char *arg, int len) +{ + char *argmem; + TfwCaPolicy *capo; + + if (tfw_capolicy_sz == TFW_CAPOLICY_ARRAY_SZ) + return NULL; + + if ((argmem = kmalloc(len + 1, GFP_KERNEL)) == NULL) + return NULL; + + capo = &tfw_capolicy[tfw_capolicy_sz++]; + capo->cmd = cmd; + capo->op = op; + capo->arg = argmem; + capo->len = len; + memcpy((void *)capo->arg, (void *)arg, len + 1); + + return capo; +} + +/* + * Add a new cache policy entry to the given location structure. + * The entry is added as a pointer into the array for all cache + * policy entries. + */ +static TfwCaPolicy * +tfw_capolicy_add(TfwLocation *loc, TfwCaPolicy *capo) +{ + if (loc->capo_sz == TFW_CAPOLICY_ARRAY_SZ) + return NULL; + loc->capo[loc->capo_sz++] = capo; + return capo; +} + +/* + * Process a cache policy directive. The directive is added to the + * current location structure. Duplicate directives are ignored but + * a warning is produced in that case. if a directive lists several + * strings to match, then an identical directive is added for each + * string that is listed. + */ +static int +tfw_handle_capolicy(TfwCfgSpec *cs, TfwCfgEntry *ce, const short cmd) +{ + int i, ret, in_len; + tfw_match_t op; + const char *in_op, *in_arg; + + BUG_ON(!tfwcfg_this_location); + BUG_ON((cmd != TFW_D_CACHE_BYPASS) && (cmd != TFW_D_CACHE_FULFILL)); + + if (ce->attr_n) { + TFW_ERR("%s: Arguments may not have the \'=\' sign\n", + cs->name); + return -EINVAL; + } + if (ce->val_n < 2) { + TFW_ERR("%s: Invalid number of arguments: %d\n", + cs->name, (int)ce->val_n); + return -EINVAL; + } + + in_op = ce->vals[0]; /* Match operator. */ + + /* Convert the match operator string to the enum value. */ + ret = tfw_cfg_map_enum(tfw_match_enum, in_op, &op); + if (ret) { + TFW_ERR("Unknown match OP: '%s %s'\n", cs->name, in_op); + return -EINVAL; + } + + /* Add each match string in the directive to the array.*/ + for (i = 1; i < ce->val_n; ++i) { + TfwCaPolicy *capo; + + in_arg = ce->vals[i]; + in_len = strlen(in_arg); + + /* Get the cache policy entry. */ + capo = tfw_capolicy_lookup(cmd, op, in_arg, in_len); + if (capo) { + TFW_WARN("%s: Duplicate entry: '%s %s %s'\n", + cs->name, cs->name, in_op, in_arg); + continue; + } + capo = tfw_capolicy_new(cmd, op, in_arg, in_len); + if (!capo) + return -ENOMEM; + /* Link the cache policy entry with the location entry. */ + if (!tfw_capolicy_add(tfwcfg_this_location, capo)) + return -ENOENT; + } + + return 0; +} + +/* + * The configuration parser has recognized the cache policy directive + * already, so there's no need to spend cycles and convert it again + * from the string to the enum value. The functions below are for + * each directive inside the location section, and for each directive + * outside of any location section. + */ +static int +tfw_handle_in_cache_fulfill(TfwCfgSpec *cs, TfwCfgEntry *ce) +{ + return tfw_handle_capolicy(cs, ce, TFW_D_CACHE_FULFILL); +} + +static int +tfw_handle_in_cache_bypass(TfwCfgSpec *cs, TfwCfgEntry *ce) +{ + return tfw_handle_capolicy(cs, ce, TFW_D_CACHE_BYPASS); +} + +static int +tfw_handle_out_cache_fulfill(TfwCfgSpec *cs, TfwCfgEntry *ce) +{ + if (!tfwcfg_this_location) + tfwcfg_this_location = &tfw_location_dflt; + return tfw_handle_capolicy(cs, ce, TFW_D_CACHE_FULFILL); +} + +static int +tfw_handle_out_cache_bypass(TfwCfgSpec *cs, TfwCfgEntry *ce) +{ + if (!tfwcfg_this_location) + tfwcfg_this_location = &tfw_location_dflt; + return tfw_handle_capolicy(cs, ce, TFW_D_CACHE_BYPASS); +} + +/* + * Find a location directive entry. The entry is looked up + * in the array that holds all location directives. + */ +static TfwLocation * +tfw_location_lookup(tfw_match_t op, const char *arg, int len) +{ + int i; + + for (i = 0; i < tfw_location_sz; ++i) { + TfwLocation *loc = &tfw_location[i]; + if ((loc->op == op) && (loc->len == len) + && !strncasecmp(loc->arg, arg, len)) + return loc; + } + + return NULL; +} + +/* + * Create and initialize a new entry for a location directive. + * The entry is placed in the array that holds all location directives. + */ +static TfwLocation * +tfw_location_new(tfw_match_t op, const char *arg, int len) +{ + char *argmem; + TfwLocation *loc; + TfwCaPolicy **capo; + size_t size = sizeof(TfwCaPolicy *) * TFW_CAPOLICY_ARRAY_SZ; + + if (tfw_location_sz == TFW_LOCATION_ARRAY_SZ) + return NULL; + + if ((argmem = kmalloc(len + 1, GFP_KERNEL)) == NULL) + return NULL; + if ((capo = kmalloc(size, GFP_KERNEL)) == NULL) { + kfree(argmem); + return NULL; + } + + loc = &tfw_location[tfw_location_sz++]; + loc->op = op; + loc->arg = argmem; + loc->len = len; + loc->capo = capo; + loc->capo_sz = 0; + memcpy((void *)loc->arg, (void *)arg, len + 1); + + return loc; +} + +/* + * Process the location directive that opens a section for cache + * policy directives in the configuration. + */ +static int +tfw_begin_location(TfwCfgSpec *cs, TfwCfgEntry *ce) +{ + int ret, in_len; + tfw_match_t op; + const char *in_op, *in_arg; + + if (ce->attr_n) { + TFW_ERR("%s: Arguments may not have the \'=\' sign\n", + cs->name); + return -EINVAL; + } + if (ce->val_n != 2) { + TFW_ERR("%s: Invalid number of arguments: %d\n", + cs->name, (int)ce->val_n); + return -EINVAL; + } + + /* Get the values of the 'location' directive. */ + in_op = ce->vals[0]; /* Match operator. */ + in_arg = ce->vals[1]; /* String for the match operator. */ + in_len = strlen(in_arg); + + /* Convert the match operator string to the enum value. */ + ret = tfw_cfg_map_enum(tfw_match_enum, in_op, &op); + if (ret) { + TFW_ERR("%s: Unknown match OP: '%s %s %s'\n", + cs->name, cs->name, in_op, in_arg); + return -EINVAL; + } + + /* Make sure the location is not a duplicate. */ + if (tfw_location_lookup(op, in_arg, in_len)) { + TFW_ERR("%s: Duplicate entry: '%s %s %s'\n", + cs->name, cs->name, in_op, in_arg); + return -EINVAL; + } + + /* Add new location and set it to be the current one. */ + tfwcfg_this_location = tfw_location_new(op, in_arg, in_len); + if (tfwcfg_this_location == NULL) { + TFW_ERR("%s: Unable to add new location: '%s %s %s'\n", + cs->name, cs->name, in_op, in_arg); + return -EINVAL; + } + + return 0; +} + +/* + * Close the section for a location directive. + */ +static int +tfw_finish_location(TfwCfgSpec *cs) +{ + BUG_ON(!tfwcfg_this_location); + tfwcfg_this_location = NULL; + return 0; +} + +/* + * Free only the memory that has been allocated while processing + * configuration directives. Make sure the memory is not freed twice. + */ +static void +__tfw_cleanup_locache(void) +{ + int i; + + for (i = 0; i < tfw_location_sz; ++i) { + TfwLocation *loc = &tfw_location[i]; + if (loc->arg) { + kfree(loc->arg); + loc->arg = NULL; + } + if (loc->capo) { + kfree(loc->capo); + loc->capo = NULL; + } + } + for (i = 0; i < tfw_capolicy_sz; ++i) { + TfwCaPolicy *capo = &tfw_capolicy[i]; + if (capo->arg) { + kfree(capo->arg); + capo->arg = NULL; + } + } +} + +static void +tfw_cleanup_locache(TfwCfgSpec *cs) +{ + __tfw_cleanup_locache(); +} + +static int +tfw_vhost_cfg_start(void) +{ + tfw_vhost_dflt.loc_sz = tfw_location_sz; + return 0; +} + +static void +tfw_vhost_cfg_stop(void) +{ + __tfw_cleanup_locache(); +} + +static TfwCfgSpec tfw_location_specs[] = { + { + "cache_bypass", NULL, + tfw_handle_in_cache_bypass, + .allow_none = true, + .allow_repeat = true, + .cleanup = tfw_cleanup_locache + }, + { + "cache_fulfill", NULL, + tfw_handle_in_cache_fulfill, + .allow_none = true, + .allow_repeat = true, + .cleanup = tfw_cleanup_locache + }, + {} +}; + +static TfwCfgSpec tfw_vhost_cfg_specs[] = { + { + "cache_bypass", NULL, + tfw_handle_out_cache_bypass, + .allow_none = true, + .allow_repeat = true, + .cleanup = tfw_cleanup_locache + }, + { + "cache_fulfill", NULL, + tfw_handle_out_cache_fulfill, + .allow_none = true, + .allow_repeat = true, + .cleanup = tfw_cleanup_locache + }, + { + "location", NULL, + tfw_cfg_handle_children, + tfw_location_specs, + &(TfwCfgSpecChild) { + .begin_hook = tfw_begin_location, + .finish_hook = tfw_finish_location + }, + .allow_none = true, + .allow_repeat = true, + /* .cleanup function in a section with + children causes a BUG_ON in cfg.c. */ + }, + {}, +}; + +TfwCfgMod tfw_vhost_cfg_mod = { + .name = "vhost", + .start = tfw_vhost_cfg_start, + .stop = tfw_vhost_cfg_stop, + .specs = tfw_vhost_cfg_specs, +}; + +int +tfw_vhost_init(void) +{ + return 0; +} + +void +tfw_vhost_exit(void) +{ + int i; + + for (i = 0; i < tfw_location_sz; ++i) + if (tfw_location[i].capo) + kfree(tfw_location[i].capo); +} diff --git a/tempesta_fw/vhost.h b/tempesta_fw/vhost.h new file mode 100644 index 0000000000..127f23e3c9 --- /dev/null +++ b/tempesta_fw/vhost.h @@ -0,0 +1,82 @@ +/** + * Tempesta FW + * + * Copyright (C) 2016 Tempesta Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __TFW_VHOST_H__ +#define __TFW_VHOST_H__ + +#include "str.h" + +/* Cache policy configuration directives. */ +typedef enum { + TFW_D_CACHE_BYPASS, + TFW_D_CACHE_FULFILL, +} tfw_capo_t; + +/* + * Cache Policy. + * + * @cmd - One of defined in tfw_capo_t. + * @op - Match operator: eq, prefix, suffix, etc. + * @arg - String for the match operator. + * @len - Length of the sting in @arg. + */ +typedef struct { + short cmd; + short op; + const char *arg; + unsigned int len; +} TfwCaPolicy; + +/* + * Group of policies by specific location. + * + * @op - Match operator: eq, prefix, suffix, etc. + * @arg - String for the match operator. + * @len - Length of the sting in @arg. + * @capo - Array of pointers to Cache Policy definitions. + * @capo_sz - Size of @capo array. + */ +typedef struct { + short op; + const char *arg; + unsigned int len; + TfwCaPolicy **capo; + unsigned int capo_sz; +} TfwLocation; + +/* + * Virtual host defined by directives and policies. + * @loc - Array of groups of policies by specific location. + * @loc_sz - Size of @loc array. + * @loc_dflt - Group of default policies. + * @loc_dflt_sz - Size of @loc_dflt. + */ +typedef struct { + TfwLocation *loc; + unsigned int loc_sz; + TfwLocation *loc_dflt; + unsigned int loc_dflt_sz; +} TfwVhost; + +TfwCaPolicy *tfw_capolicy_match(TfwLocation *loc, TfwStr *arg); +TfwLocation *tfw_location_match(TfwVhost *vhost, TfwStr *arg); +TfwVhost *tfw_vhost_match(TfwStr *arg); +TfwVhost *tfw_vhost_get_default(void); + +#endif /* __TFW_VHOST_H__ */