X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;ds=sidebyside;f=lustre%2Fptlrpc%2Fsec_config.c;h=920a1d28672d485bbe7486ce076a387d97b2ec3e;hb=5315db3f1066619d6effe4f778d2df3ad1ba738f;hp=67287e8e46b351899803f21e02d95427eb0f4208;hpb=6869932b552ac705f411de3362f01bd50c1f6f7d;p=fs%2Flustre-release.git diff --git a/lustre/ptlrpc/sec_config.c b/lustre/ptlrpc/sec_config.c index 67287e8..920a1d2 100644 --- a/lustre/ptlrpc/sec_config.c +++ b/lustre/ptlrpc/sec_config.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -17,43 +15,36 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ * Lustre is a trademark of Sun Microsystems, Inc. */ -#ifndef EXPORT_SYMTAB -#define EXPORT_SYMTAB -#endif #define DEBUG_SUBSYSTEM S_SEC #include -#ifndef __KERNEL__ -#include -#include -#else #include #include -#endif #include #include #include #include #include +#include +#include #include +#include #include #include "ptlrpc_internal.h" @@ -67,6 +58,8 @@ const char *sptlrpc_part2name(enum lustre_sec_part part) return "mdt"; case LUSTRE_SP_OST: return "ost"; + case LUSTRE_SP_MGC: + return "mgc"; case LUSTRE_SP_MGS: return "mgs"; case LUSTRE_SP_ANY: @@ -91,236 +84,88 @@ enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd) CERROR("unknown target %p(%s)\n", obd, type); return LUSTRE_SP_ANY; } -EXPORT_SYMBOL(sptlrpc_target_sec_part); /**************************************** * user supplied flavor string parsing * ****************************************/ -#ifdef HAVE_ADLER -#define BULK_HASH_ALG_DEFAULT BULK_HASH_ALG_ADLER32 -#else -#define BULK_HASH_ALG_DEFAULT BULK_HASH_ALG_CRC32 -#endif - -typedef enum { - BULK_TYPE_N = 0, - BULK_TYPE_I = 1, - BULK_TYPE_P = 2 -} bulk_type_t; - -static void get_default_flavor(struct sptlrpc_flavor *sf) -{ - sf->sf_rpc = SPTLRPC_FLVR_NULL; - sf->sf_bulk_ciph = BULK_CIPH_ALG_NULL; - sf->sf_bulk_hash = BULK_HASH_ALG_NULL; - sf->sf_flags = 0; -} - -static void get_flavor_by_rpc(struct sptlrpc_rule *rule, __u16 rpc_flavor) -{ - get_default_flavor(&rule->sr_flvr); - - rule->sr_flvr.sf_rpc = rpc_flavor; - - switch (rpc_flavor) { - case SPTLRPC_FLVR_NULL: - break; - case SPTLRPC_FLVR_PLAIN: - case SPTLRPC_FLVR_KRB5N: - case SPTLRPC_FLVR_KRB5A: - rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_DEFAULT; - break; - case SPTLRPC_FLVR_KRB5P: - rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128; - /* fall through */ - case SPTLRPC_FLVR_KRB5I: - rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1; - break; - default: - LBUG(); - } -} - -static void get_flavor_by_bulk(struct sptlrpc_rule *rule, - __u16 rpc_flavor, bulk_type_t bulk_type) -{ - switch (bulk_type) { - case BULK_TYPE_N: - rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL; - rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL; - break; - case BULK_TYPE_I: - switch (rpc_flavor) { - case SPTLRPC_FLVR_PLAIN: - case SPTLRPC_FLVR_KRB5N: - case SPTLRPC_FLVR_KRB5A: - rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_DEFAULT; - break; - case SPTLRPC_FLVR_KRB5I: - case SPTLRPC_FLVR_KRB5P: - rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1; - break; - default: - LBUG(); - } - rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL; - break; - case BULK_TYPE_P: - rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1; - rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128; - break; - default: - LBUG(); - } -} - -static __u16 __flavors[] = { - SPTLRPC_FLVR_NULL, - SPTLRPC_FLVR_PLAIN, - SPTLRPC_FLVR_KRB5N, - SPTLRPC_FLVR_KRB5A, - SPTLRPC_FLVR_KRB5I, - SPTLRPC_FLVR_KRB5P, -}; - -#define __nflavors ARRAY_SIZE(__flavors) - /* - * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]] - * for examples: - * null - * plain-bulki - * krb5p-bulkn - * krb5i-bulkp - * krb5i-bulkp:sha512/arc4 + * format: [-] */ -static int parse_flavor(char *str, struct sptlrpc_rule *rule) +int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr) { - const char *f; - char *bulk, *alg, *enc; - char buf[64]; - bulk_type_t bulk_type; - __u8 i; - ENTRY; + char buf[32]; + char *bulk, *alg; - if (str == NULL || str[0] == '\0') { - rule->sr_flvr.sf_rpc = SPTLRPC_FLVR_INVALID; - goto out; - } + memset(flvr, 0, sizeof(*flvr)); - for (i = 0; i < __nflavors; i++) { - f = sptlrpc_rpcflavor2name(__flavors[i]); - if (strncmp(str, f, strlen(f)) == 0) - break; + if (str == NULL || str[0] == '\0') { + flvr->sf_rpc = SPTLRPC_FLVR_INVALID; + return 0; } - if (i >= __nflavors) - GOTO(invalid, -EINVAL); - - /* prepare local buffer thus we can modify it as we want */ - strncpy(buf, str, 64); - buf[64 - 1] = '\0'; + strlcpy(buf, str, sizeof(buf)); - /* find bulk string */ bulk = strchr(buf, '-'); if (bulk) *bulk++ = '\0'; - /* now the first part must equal to rpc flavor name */ - if (strcmp(buf, f) != 0) - GOTO(invalid, -EINVAL); - - get_flavor_by_rpc(rule, __flavors[i]); - - if (bulk == NULL) - goto out; - - /* find bulk algorithm string */ - alg = strchr(bulk, ':'); - if (alg) - *alg++ = '\0'; - - /* verify bulk section */ - if (strcmp(bulk, "bulkn") == 0) { - rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL; - rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL; - bulk_type = BULK_TYPE_N; - } else if (strcmp(bulk, "bulki") == 0) - bulk_type = BULK_TYPE_I; - else if (strcmp(bulk, "bulkp") == 0) - bulk_type = BULK_TYPE_P; - else - GOTO(invalid, -EINVAL); - - /* null flavor don't support bulk i/p */ - if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N) - GOTO(invalid, -EINVAL); - - /* plain policy dosen't support bulk p */ - if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P) - GOTO(invalid, -EINVAL); - - get_flavor_by_bulk(rule, __flavors[i], bulk_type); - - if (alg == NULL) - goto out; - - /* find encryption algorithm string */ - enc = strchr(alg, '/'); - if (enc) - *enc++ = '\0'; - - /* checksum algorithm */ - for (i = 0; i < BULK_HASH_ALG_MAX; i++) { - if (strcmp(alg, sptlrpc_get_hash_name(i)) == 0) { - rule->sr_flvr.sf_bulk_hash = i; - break; - } - } - if (i >= BULK_HASH_ALG_MAX) - GOTO(invalid, -EINVAL); - - /* privacy algorithm */ - if (enc) { - for (i = 0; i < BULK_CIPH_ALG_MAX; i++) { - if (strcmp(enc, sptlrpc_get_ciph_name(i)) == 0) { - rule->sr_flvr.sf_bulk_ciph = i; - break; - } - } - if (i >= BULK_CIPH_ALG_MAX) - GOTO(invalid, -EINVAL); - } + flvr->sf_rpc = sptlrpc_name2flavor_base(buf); + if (flvr->sf_rpc == SPTLRPC_FLVR_INVALID) + goto err_out; /* - * bulk combination sanity checks + * currently only base flavor "plain" can have bulk specification. */ - if (bulk_type == BULK_TYPE_P && - rule->sr_flvr.sf_bulk_ciph == BULK_CIPH_ALG_NULL) - GOTO(invalid, -EINVAL); - - if (bulk_type == BULK_TYPE_I && - (rule->sr_flvr.sf_bulk_hash == BULK_HASH_ALG_NULL || - rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL)) - GOTO(invalid, -EINVAL); + if (flvr->sf_rpc == SPTLRPC_FLVR_PLAIN) { + flvr->u_bulk.hash.hash_alg = BULK_HASH_ALG_ADLER32; + if (bulk) { + /* + * format: plain-hash: + */ + alg = strchr(bulk, ':'); + if (alg == NULL) + goto err_out; + *alg++ = '\0'; + + if (strcmp(bulk, "hash")) + goto err_out; + + flvr->u_bulk.hash.hash_alg = sptlrpc_get_hash_alg(alg); + if (flvr->u_bulk.hash.hash_alg >= BULK_HASH_ALG_MAX) + goto err_out; + } - if (bulk_type == BULK_TYPE_N && - (rule->sr_flvr.sf_bulk_hash != BULK_HASH_ALG_NULL || - rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL)) - GOTO(invalid, -EINVAL); + if (flvr->u_bulk.hash.hash_alg == BULK_HASH_ALG_NULL) + flvr_set_bulk_svc(&flvr->sf_rpc, SPTLRPC_BULK_SVC_NULL); + else + flvr_set_bulk_svc(&flvr->sf_rpc, SPTLRPC_BULK_SVC_INTG); + } else { + if (bulk) + goto err_out; + } -out: + flvr->sf_flags = 0; return 0; -invalid: + +err_out: CERROR("invalid flavor string: %s\n", str); return -EINVAL; } +EXPORT_SYMBOL(sptlrpc_parse_flavor); /**************************************** * configure rules * ****************************************/ +static void get_default_flavor(struct sptlrpc_flavor *sf) +{ + memset(sf, 0, sizeof(*sf)); + + sf->sf_rpc = SPTLRPC_FLVR_NULL; + sf->sf_flags = 0; +} + static void sptlrpc_rule_init(struct sptlrpc_rule *rule) { rule->sr_netid = LNET_NIDNET(LNET_NID_ANY); @@ -382,7 +227,7 @@ int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule) } /* 2.1 flavor */ - rc = parse_flavor(flavor, rule); + rc = sptlrpc_parse_flavor(flavor, &rule->sr_flvr); if (rc) RETURN(-EINVAL); @@ -405,41 +250,37 @@ EXPORT_SYMBOL(sptlrpc_rule_set_free); /* * return 0 if the rule set could accomodate one more rule. - * if @expand != 0, the rule set might be expanded. */ -int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand) +int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset) { - struct sptlrpc_rule *rules; - int nslot; + struct sptlrpc_rule *rules; + int nslot; - if (rset->srs_nrule < rset->srs_nslot) - return 0; + might_sleep(); - if (expand == 0) - return -E2BIG; + if (rset->srs_nrule < rset->srs_nslot) + return 0; - if (rset->srs_nslot == 0) - nslot = 8; - else - nslot = rset->srs_nslot + 8; + nslot = rset->srs_nslot + 8; /* better use realloc() if available */ OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules)); if (rules == NULL) return -ENOMEM; - memcpy(rules, rset->srs_rules, - rset->srs_nrule * sizeof(*rset->srs_rules)); + if (rset->srs_nrule) { + LASSERT(rset->srs_nslot && rset->srs_rules); + memcpy(rules, rset->srs_rules, + rset->srs_nrule * sizeof(*rset->srs_rules)); - if (rset->srs_rules) OBD_FREE(rset->srs_rules, rset->srs_nslot * sizeof(*rset->srs_rules)); + } rset->srs_rules = rules; rset->srs_nslot = nslot; return 0; } -EXPORT_SYMBOL(sptlrpc_rule_set_expand); static inline int rule_spec_dir(struct sptlrpc_rule *rule) { @@ -463,18 +304,19 @@ static inline int rule_match_net(struct sptlrpc_rule *r1, /* * merge @rule into @rset. - * if @expand != 0 then @rset slots might be expanded. + * the @rset slots might be expanded. */ int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset, - struct sptlrpc_rule *rule, - int expand) + struct sptlrpc_rule *rule) { - struct sptlrpc_rule *p = rset->srs_rules; - int spec_dir, spec_net; - int rc, n, match = 0; + struct sptlrpc_rule *p = rset->srs_rules; + int spec_dir, spec_net; + int rc, n, match = 0; + + might_sleep(); - spec_net = rule_spec_net(rule); - spec_dir = rule_spec_dir(rule); + spec_net = rule_spec_net(rule); + spec_dir = rule_spec_dir(rule); for (n = 0; n < rset->srs_nrule; n++) { p = &rset->srs_rules[n]; @@ -532,7 +374,7 @@ int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset, LASSERT(n >= 0 && n <= rset->srs_nrule); if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) { - rc = sptlrpc_rule_set_expand(rset, expand); + rc = sptlrpc_rule_set_expand(rset); if (rc) return rc; @@ -543,7 +385,7 @@ int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset, memcpy(&rset->srs_rules[n], rule, sizeof(*rule)); rset->srs_nrule++; } else { - CWARN("ignore the unmatched deletion\n"); + CDEBUG(D_CONFIG, "ignore the unmatched deletion\n"); } } @@ -551,35 +393,15 @@ int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset, } EXPORT_SYMBOL(sptlrpc_rule_set_merge); -int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset, - struct sptlrpc_conf_log *log) -{ - LASSERT(rset); - LASSERT(log); - - sptlrpc_rule_set_free(rset); - - if (log->scl_nrule == 0) - return 0; - - OBD_ALLOC(rset->srs_rules, log->scl_nrule * sizeof(*log->scl_rules)); - if (!rset->srs_rules) - return -ENOMEM; - - memcpy(rset->srs_rules, log->scl_rules, - log->scl_nrule * sizeof(*log->scl_rules)); - rset->srs_nslot = rset->srs_nrule = log->scl_nrule; - return 0; -} -EXPORT_SYMBOL(sptlrpc_rule_set_from_log); - -/* - * according to NID/from choose a flavor from rule set. +/** + * given from/to/nid, determine a matching flavor in ruleset. + * return 1 if a match found, otherwise return 0. */ -void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset, - enum lustre_sec_part from, - lnet_nid_t nid, - struct sptlrpc_flavor *sf) +int sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset, + enum lustre_sec_part from, + enum lustre_sec_part to, + lnet_nid_t nid, + struct sptlrpc_flavor *sf) { struct sptlrpc_rule *r; int n; @@ -596,14 +418,16 @@ void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset, from != r->sr_from) continue; + if (to != LUSTRE_SP_ANY && r->sr_to != LUSTRE_SP_ANY && + to != r->sr_to) + continue; + *sf = r->sr_flvr; - return; + return 1; } - /* no match found, set as default flavor */ - get_default_flavor(sf); + return 0; } -EXPORT_SYMBOL(sptlrpc_rule_set_choose); void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset) { @@ -612,81 +436,27 @@ void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset) for (n = 0; n < rset->srs_nrule; n++) { r = &rset->srs_rules[n]; - CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n, - r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc); + CDEBUG(D_SEC, "<%02d> from %x to %x, net %x, rpc %x\n", n, + r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc); } } -EXPORT_SYMBOL(sptlrpc_rule_set_dump); - -/**************************************** - * sptlrpc config log * - ****************************************/ -struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void) +static int sptlrpc_rule_set_extract(struct sptlrpc_rule_set *gen, + struct sptlrpc_rule_set *tgt, + enum lustre_sec_part from, + enum lustre_sec_part to, + struct sptlrpc_rule_set *rset) { - struct sptlrpc_conf_log *log; - - OBD_ALLOC_PTR(log); - if (log == NULL) - return ERR_PTR(-ENOMEM); - - log->scl_max = SPTLRPC_CONF_LOG_MAX; - return log; -} -EXPORT_SYMBOL(sptlrpc_conf_log_alloc); - -void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log) -{ - LASSERT(log->scl_max == SPTLRPC_CONF_LOG_MAX); - OBD_FREE_PTR(log); -} -EXPORT_SYMBOL(sptlrpc_conf_log_free); + struct sptlrpc_rule_set *src[2] = { gen, tgt }; + struct sptlrpc_rule *rule; + int i, n, rc; -static __u32 get_log_rule_flags(enum lustre_sec_part from, - enum lustre_sec_part to, - unsigned int fl_udesc) -{ - /* MDT->MDT; MDT->OST */ - if (from == LUSTRE_SP_MDT) - return PTLRPC_SEC_FL_ROOTONLY; - /* CLI->OST */ - if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST) - return PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK; - /* CLI->MDT */ - if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT) - if (fl_udesc) - return PTLRPC_SEC_FL_UDESC; - - return 0; -} + might_sleep(); -/* - * generate config log: merge general and target rules, which - * match @from @to - */ -int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen, - struct sptlrpc_rule_set *tgt, - enum lustre_sec_part from, - enum lustre_sec_part to, - unsigned int fl_udesc, - struct sptlrpc_conf_log *log) -{ - struct sptlrpc_rule_set *src[2] = { gen, tgt }; - struct sptlrpc_rule_set dst; - struct sptlrpc_rule *rule; - __u32 flags; - int i, n, rc; - - LASSERT(log); - - dst.srs_nslot = log->scl_max; - dst.srs_nrule = 0; - dst.srs_rules = log->scl_rules; - - /* merge general rules firstly, then target-specific rules */ - for (i = 0; i < 2; i++) { - if (src[i] == NULL) - continue; + /* merge general rules firstly, then target-specific rules */ + for (i = 0; i < 2; i++) { + if (src[i] == NULL) + continue; for (n = 0; n < src[i]->srs_nrule; n++) { rule = &src[i]->srs_rules[n]; @@ -700,7 +470,7 @@ int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen, rule->sr_to != to) continue; - rc = sptlrpc_rule_set_merge(&dst, rule, 0); + rc = sptlrpc_rule_set_merge(rset, rule); if (rc) { CERROR("can't merge: %d\n", rc); return rc; @@ -708,125 +478,507 @@ int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen, } } - log->scl_nrule = dst.srs_nrule; + return 0; +} - /* set flags for each rule */ - flags = get_log_rule_flags(from, to, fl_udesc); +/********************************** + * sptlrpc configuration support * + **********************************/ - for (i = 0; i < log->scl_nrule; i++) { - log->scl_rules[i].sr_flvr.sf_flags = flags; +struct sptlrpc_conf_tgt { + struct list_head sct_list; + char sct_name[MAX_OBD_NAME]; + struct sptlrpc_rule_set sct_rset; +}; - /* also clear the from/to fields which don't need to be known - * accordingly. @from == ANY means this log is for target, - * otherwise for client. */ - if (from != LUSTRE_SP_ANY) - log->scl_rules[i].sr_from = LUSTRE_SP_ANY; - log->scl_rules[i].sr_to = LUSTRE_SP_ANY; - } +struct sptlrpc_conf { + struct list_head sc_list; + char sc_fsname[MTI_NAME_MAXLEN]; + unsigned int sc_modified; /* modified during updating */ + unsigned int sc_updated:1, /* updated copy from MGS */ + sc_local:1; /* local copy from target */ + struct sptlrpc_rule_set sc_rset; /* fs general rules */ + struct list_head sc_tgts; /* target-specific rules */ +}; - return 0; +static struct mutex sptlrpc_conf_lock; +static LIST_HEAD(sptlrpc_confs); + +static void sptlrpc_conf_free_rsets(struct sptlrpc_conf *conf) +{ + struct sptlrpc_conf_tgt *conf_tgt, *conf_tgt_next; + + sptlrpc_rule_set_free(&conf->sc_rset); + + list_for_each_entry_safe(conf_tgt, conf_tgt_next, + &conf->sc_tgts, sct_list) { + sptlrpc_rule_set_free(&conf_tgt->sct_rset); + list_del(&conf_tgt->sct_list); + OBD_FREE_PTR(conf_tgt); + } + LASSERT(list_empty(&conf->sc_tgts)); + + conf->sc_updated = 0; + conf->sc_local = 0; } -EXPORT_SYMBOL(sptlrpc_conf_log_populate); -/* - * extract config log from @lcfg - */ -struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg) +static void sptlrpc_conf_free(struct sptlrpc_conf *conf) { - struct sptlrpc_conf_log *log; - struct sptlrpc_rule *r; - int i; - ENTRY; + CDEBUG(D_SEC, "free sptlrpc conf %s\n", conf->sc_fsname); + + sptlrpc_conf_free_rsets(conf); + list_del(&conf->sc_list); + OBD_FREE_PTR(conf); +} - log = lustre_cfg_buf(lcfg, 1); - if (log == NULL) { - CERROR("no sptlrpc config data\n"); - RETURN(ERR_PTR(-EINVAL)); +static +struct sptlrpc_conf_tgt *sptlrpc_conf_get_tgt(struct sptlrpc_conf *conf, + const char *name, + int create) +{ + struct sptlrpc_conf_tgt *conf_tgt; + + list_for_each_entry(conf_tgt, &conf->sc_tgts, sct_list) { + if (strcmp(conf_tgt->sct_name, name) == 0) + return conf_tgt; } - if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) { - __swab32s(&log->scl_max); - __swab32s(&log->scl_nrule); + if (!create) + return NULL; + + OBD_ALLOC_PTR(conf_tgt); + if (conf_tgt) { + strlcpy(conf_tgt->sct_name, name, sizeof(conf_tgt->sct_name)); + sptlrpc_rule_set_init(&conf_tgt->sct_rset); + list_add(&conf_tgt->sct_list, &conf->sc_tgts); } - if (LUSTRE_CFG_BUFLEN(lcfg, 1) < - log->scl_max * sizeof(log->scl_rules[0])) { - CERROR("mal-formed config log\n"); - RETURN(ERR_PTR(-EINVAL)); + return conf_tgt; +} + +static +struct sptlrpc_conf *sptlrpc_conf_get(const char *fsname, + int create) +{ + struct sptlrpc_conf *conf; + + list_for_each_entry(conf, &sptlrpc_confs, sc_list) { + if (strcmp(conf->sc_fsname, fsname) == 0) + return conf; } - if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) { - for (i = 0; i < log->scl_nrule; i++) { - r = &log->scl_rules[i]; - __swab32s(&r->sr_netid); - __swab16s(&r->sr_flvr.sf_rpc); - __swab32s(&r->sr_flvr.sf_flags); + if (!create) + return NULL; + + OBD_ALLOC_PTR(conf); + if (conf == NULL) + return NULL; + + if (strlcpy(conf->sc_fsname, fsname, sizeof(conf->sc_fsname)) >= + sizeof(conf->sc_fsname)) { + OBD_FREE_PTR(conf); + return NULL; + } + sptlrpc_rule_set_init(&conf->sc_rset); + INIT_LIST_HEAD(&conf->sc_tgts); + list_add(&conf->sc_list, &sptlrpc_confs); + + CDEBUG(D_SEC, "create sptlrpc conf %s\n", conf->sc_fsname); + return conf; +} + +/** + * caller must hold conf_lock already. + */ +static int sptlrpc_conf_merge_rule(struct sptlrpc_conf *conf, + const char *target, + struct sptlrpc_rule *rule) +{ + struct sptlrpc_conf_tgt *conf_tgt; + struct sptlrpc_rule_set *rule_set; + + /* fsname == target means general rules for the whole fs */ + if (strcmp(conf->sc_fsname, target) == 0) { + rule_set = &conf->sc_rset; + } else { + conf_tgt = sptlrpc_conf_get_tgt(conf, target, 1); + if (conf_tgt) { + rule_set = &conf_tgt->sct_rset; + } else { + CERROR("out of memory, can't merge rule!\n"); + return -ENOMEM; } } - RETURN(log); + return sptlrpc_rule_set_merge(rule_set, rule); } -EXPORT_SYMBOL(sptlrpc_conf_log_extract); -void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log) +/** + * process one LCFG_SPTLRPC_CONF record. if \a conf is NULL, we + * find one through the target name in the record inside conf_lock; + * otherwise means caller already hold conf_lock. + */ +static int __sptlrpc_process_config(char *target, const char *fsname, + struct sptlrpc_rule *rule, + struct sptlrpc_conf *conf) { - log->scl_nrule = 0; - memset(log->scl_rules, 0, sizeof(log->scl_rules)); + int rc; + + ENTRY; + if (!conf) { + if (!fsname) + return -ENODEV; + + mutex_lock(&sptlrpc_conf_lock); + conf = sptlrpc_conf_get(fsname, 0); + if (!conf) { + CERROR("can't find conf\n"); + rc = -ENOMEM; + } else { + rc = sptlrpc_conf_merge_rule(conf, target, rule); + } + mutex_unlock(&sptlrpc_conf_lock); + } else { + LASSERT(mutex_is_locked(&sptlrpc_conf_lock)); + rc = sptlrpc_conf_merge_rule(conf, target, rule); + } + + if (!rc) + conf->sc_modified++; + + RETURN(rc); } -EXPORT_SYMBOL(sptlrpc_conf_log_cleanup); -void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log) +int sptlrpc_process_config(struct lustre_cfg *lcfg) { - struct sptlrpc_rule *r; - int n; + char fsname[MTI_NAME_MAXLEN]; + struct sptlrpc_rule rule; + char *target, *param; + int rc; + + print_lustre_cfg(lcfg); + + target = lustre_cfg_string(lcfg, 1); + if (!target) { + CERROR("missing target name\n"); + return -EINVAL; + } + + param = lustre_cfg_string(lcfg, 2); + if (!param) { + CERROR("missing parameter\n"); + return -EINVAL; + } + + /* parse rule to make sure the format is correct */ + if (strncmp(param, PARAM_SRPC_FLVR, + sizeof(PARAM_SRPC_FLVR) - 1) != 0) { + CERROR("Invalid sptlrpc parameter: %s\n", param); + return -EINVAL; + } + param += sizeof(PARAM_SRPC_FLVR) - 1; + + CDEBUG(D_SEC, "processing rule: %s.%s\n", target, param); + + /* + * Three types of targets exist for sptlrpc using conf_param + * 1. '_mgs' which targets mgc srpc settings. Treat it as + * as a special file system name. + * 2. target is a device which can be fsname-MDTXXXX or + * fsname-OSTXXXX. This can be verified by the function + * server_name2fsname. + * 3. If both above conditions are not meet then the target + * is a actual filesystem. + */ + if (server_name2fsname(target, fsname, NULL)) + strlcpy(fsname, target, sizeof(target)); + + rc = sptlrpc_parse_rule(param, &rule); + if (rc) + return rc; + + return __sptlrpc_process_config(target, fsname, &rule, NULL); +} +EXPORT_SYMBOL(sptlrpc_process_config); - CWARN("max %u, rule# %u part %u\n", - log->scl_max, log->scl_nrule, log->scl_part); +static int logname2fsname(const char *logname, char *buf, int buflen) +{ + char *ptr; + int len; - for (n = 0; n < log->scl_nrule; n++) { - r = &log->scl_rules[n]; - CWARN("<%02d> %x -> %x, net %x, rpc %x\n", n, - r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc); + ptr = strrchr(logname, '-'); + if (ptr == NULL || strcmp(ptr, "-sptlrpc")) { + CERROR("%s is not a sptlrpc config log\n", logname); + return -EINVAL; } + + len = min((int) (ptr - logname), buflen - 1); + + memcpy(buf, logname, len); + buf[len] = '\0'; + return 0; } -EXPORT_SYMBOL(sptlrpc_conf_log_dump); -/* - * caller should guarantee that no concurrent calls to this function +void sptlrpc_conf_log_update_begin(const char *logname) +{ + struct sptlrpc_conf *conf; + char fsname[16]; + + if (logname2fsname(logname, fsname, sizeof(fsname))) + return; + + mutex_lock(&sptlrpc_conf_lock); + + conf = sptlrpc_conf_get(fsname, 0); + if (conf) { + if (conf->sc_local) { + LASSERT(conf->sc_updated == 0); + sptlrpc_conf_free_rsets(conf); + } + conf->sc_modified = 0; + } + + mutex_unlock(&sptlrpc_conf_lock); +} +EXPORT_SYMBOL(sptlrpc_conf_log_update_begin); + +/** + * mark a config log has been updated */ -#define SEC_ADAPT_DELAY (10) +void sptlrpc_conf_log_update_end(const char *logname) +{ + struct sptlrpc_conf *conf; + char fsname[16]; + + if (logname2fsname(logname, fsname, sizeof(fsname))) + return; + + mutex_lock(&sptlrpc_conf_lock); + + conf = sptlrpc_conf_get(fsname, 0); + if (conf) { + /* + * if original state is not updated, make sure the + * modified counter > 0 to enforce updating local copy. + */ + if (conf->sc_updated == 0) + conf->sc_modified++; + + conf->sc_updated = 1; + } -int sptlrpc_cliobd_process_config(struct obd_device *obd, - struct lustre_cfg *lcfg) + mutex_unlock(&sptlrpc_conf_lock); +} +EXPORT_SYMBOL(sptlrpc_conf_log_update_end); + +void sptlrpc_conf_log_start(const char *logname) +{ + char fsname[16]; + + if (logname2fsname(logname, fsname, sizeof(fsname))) + return; + + mutex_lock(&sptlrpc_conf_lock); + sptlrpc_conf_get(fsname, 1); + mutex_unlock(&sptlrpc_conf_lock); +} +EXPORT_SYMBOL(sptlrpc_conf_log_start); + +void sptlrpc_conf_log_stop(const char *logname) { - struct sptlrpc_conf_log *log; - struct obd_import *imp; - int rc; + struct sptlrpc_conf *conf; + char fsname[16]; + + if (logname2fsname(logname, fsname, sizeof(fsname))) + return; - log = sptlrpc_conf_log_extract(lcfg); - if (IS_ERR(log)) { - CERROR("extract log error: %ld\n", PTR_ERR(log)); - return PTR_ERR(log); + mutex_lock(&sptlrpc_conf_lock); + conf = sptlrpc_conf_get(fsname, 0); + if (conf) + sptlrpc_conf_free(conf); + mutex_unlock(&sptlrpc_conf_lock); +} +EXPORT_SYMBOL(sptlrpc_conf_log_stop); + +static void inline flavor_set_flags(struct sptlrpc_flavor *sf, + enum lustre_sec_part from, + enum lustre_sec_part to, + unsigned int fl_udesc) +{ + /* + * null flavor doesn't need to set any flavor, and in fact + * we'd better not do that because everybody share a single sec. + */ + if (sf->sf_rpc == SPTLRPC_FLVR_NULL) + return; + + if (from == LUSTRE_SP_MDT) { + /* MDT->MDT; MDT->OST */ + sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY; + } else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST) { + /* CLI->OST */ + sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK; + } else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT) { + /* CLI->MDT */ + if (fl_udesc && sf->sf_rpc != SPTLRPC_FLVR_NULL) + sf->sf_flags |= PTLRPC_SEC_FL_UDESC; } - obd->u.cli.cl_sec_part = log->scl_part; + /* Some flavors use a single uid (0) context */ + if (flvr_is_rootonly(sf->sf_rpc)) + sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY; - rc = sptlrpc_rule_set_from_log(&obd->u.cli.cl_sptlrpc_rset, log); - if (rc) { - CERROR("failed create rule set: %d\n", rc); - return rc; + /* User descriptor might need to be cleared */ + if (flvr_allows_user_desc(sf->sf_rpc) == 0) + sf->sf_flags &= ~PTLRPC_SEC_FL_UDESC; +} + +void sptlrpc_conf_choose_flavor(enum lustre_sec_part from, + enum lustre_sec_part to, + struct obd_uuid *target, + lnet_nid_t nid, + struct sptlrpc_flavor *sf) +{ + struct sptlrpc_conf *conf; + struct sptlrpc_conf_tgt *conf_tgt; + char name[MTI_NAME_MAXLEN]; + int len, rc = 0; + + obd_uuid2fsname(name, target->uuid, sizeof(name)); + + mutex_lock(&sptlrpc_conf_lock); + + conf = sptlrpc_conf_get(name, 0); + if (conf == NULL) + goto out; + + /* convert uuid name (supposed end with _UUID) to target name */ + len = strlen(target->uuid); + LASSERT(len > 5); + memcpy(name, target->uuid, len - 5); + name[len - 5] = '\0'; + + conf_tgt = sptlrpc_conf_get_tgt(conf, name, 0); + if (conf_tgt) { + rc = sptlrpc_rule_set_choose(&conf_tgt->sct_rset, + from, to, nid, sf); + if (rc) + goto out; } - imp = obd->u.cli.cl_import; - if (imp == NULL) - return 0; + rc = sptlrpc_rule_set_choose(&conf->sc_rset, from, to, nid, sf); +out: + mutex_unlock(&sptlrpc_conf_lock); - /* even if imp_sec_expire is already set, we'll override it to a - * newer (later) time */ - spin_lock(&imp->imp_lock); - if (imp->imp_sec) - imp->imp_sec_expire = cfs_time_current_sec() + SEC_ADAPT_DELAY; - spin_unlock(&imp->imp_lock); - return 0; + if (rc == 0) + get_default_flavor(sf); + + flavor_set_flags(sf, from, to, 1); +} + +/** + * called by target devices, determine the expected flavor from + * certain peer (from, nid). + */ +void sptlrpc_target_choose_flavor(struct sptlrpc_rule_set *rset, + enum lustre_sec_part from, + lnet_nid_t nid, + struct sptlrpc_flavor *sf) +{ + if (sptlrpc_rule_set_choose(rset, from, LUSTRE_SP_ANY, nid, sf) == 0) + get_default_flavor(sf); +} + +#define SEC_ADAPT_DELAY (10) + +/** + * called by client devices, notify the sptlrpc config has changed and + * do import_sec_adapt later. + */ +void sptlrpc_conf_client_adapt(struct obd_device *obd) +{ + struct obd_import *imp; + ENTRY; + + LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 || + strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) == 0 || + strcmp(obd->obd_type->typ_name, LUSTRE_OSP_NAME) == 0 || + strcmp(obd->obd_type->typ_name, LUSTRE_LWP_NAME) == 0); + CDEBUG(D_SEC, "obd %s\n", obd->u.cli.cl_target_uuid.uuid); + + /* serialize with connect/disconnect import */ + down_read_nested(&obd->u.cli.cl_sem, OBD_CLI_SEM_MDCOSC); + + imp = obd->u.cli.cl_import; + if (imp) { + write_lock(&imp->imp_sec_lock); + if (imp->imp_sec) + imp->imp_sec_expire = ktime_get_real_seconds() + + SEC_ADAPT_DELAY; + write_unlock(&imp->imp_sec_lock); + } + + up_read(&obd->u.cli.cl_sem); + EXIT; +} +EXPORT_SYMBOL(sptlrpc_conf_client_adapt); + +/** + * called by target devices, extract sptlrpc rules which applies to + * this target, to be used for future rpc flavor checking. + */ +int sptlrpc_conf_target_get_rules(struct obd_device *obd, + struct sptlrpc_rule_set *rset) +{ + struct sptlrpc_conf *conf; + struct sptlrpc_conf_tgt *conf_tgt; + enum lustre_sec_part sp_dst; + char fsname[MTI_NAME_MAXLEN]; + int rc = 0; + ENTRY; + + if (strcmp(obd->obd_type->typ_name, LUSTRE_MDT_NAME) == 0) { + sp_dst = LUSTRE_SP_MDT; + } else if (strcmp(obd->obd_type->typ_name, LUSTRE_OST_NAME) == 0) { + sp_dst = LUSTRE_SP_OST; + } else { + CERROR("unexpected obd type %s\n", obd->obd_type->typ_name); + RETURN(-EINVAL); + } + + obd_uuid2fsname(fsname, obd->obd_uuid.uuid, sizeof(fsname)); + + mutex_lock(&sptlrpc_conf_lock); + conf = sptlrpc_conf_get(fsname, 0); + if (conf == NULL) { + CERROR("missing sptlrpc config log\n"); + rc = -EFAULT; + } else { + /* extract rule set for this target */ + conf_tgt = sptlrpc_conf_get_tgt(conf, obd->obd_name, 0); + + rc = sptlrpc_rule_set_extract(&conf->sc_rset, + conf_tgt ? &conf_tgt->sct_rset : NULL, + LUSTRE_SP_ANY, sp_dst, rset); + } + mutex_unlock(&sptlrpc_conf_lock); + + RETURN(rc); +} + +int sptlrpc_conf_init(void) +{ + mutex_init(&sptlrpc_conf_lock); + return 0; +} + +void sptlrpc_conf_fini(void) +{ + struct sptlrpc_conf *conf, *conf_next; + + mutex_lock(&sptlrpc_conf_lock); + list_for_each_entry_safe(conf, conf_next, &sptlrpc_confs, sc_list) + sptlrpc_conf_free(conf); + LASSERT(list_empty(&sptlrpc_confs)); + mutex_unlock(&sptlrpc_conf_lock); } -EXPORT_SYMBOL(sptlrpc_cliobd_process_config);