summaryrefslogtreecommitdiffstats
path: root/lib/rules/api.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rules/api.c')
-rw-r--r--lib/rules/api.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/lib/rules/api.c b/lib/rules/api.c
index b8f27b55..e37efdd8 100644
--- a/lib/rules/api.c
+++ b/lib/rules/api.c
@@ -27,6 +27,8 @@ struct kr_rules *the_rules = NULL;
/* DB key-space summary
- "\0" starts special keys like "\0rulesets" or "\0stamp"
+ - "\0tagBits" -> kr_rule_tags_t denoting the set of tags that have a name in DB
+ - "\0tag_" + tag name -> one byte with the tag's number
- some future additions?
- otherwise it's rulesets - each has a prefix, e.g. RULESET_DEFAULT,
its length is bounded by KEY_RULESET_MAXLEN - 1; after that prefix:
@@ -64,6 +66,91 @@ static int answer_zla_empty(struct kr_query *qry, knot_pkt_t *pkt,
static int answer_zla_redirect(struct kr_query *qry, knot_pkt_t *pkt, const char *ruleset_name,
knot_db_val_t zla_lf, knot_db_val_t val);
+// LATER: doing tag_names_default() and kr_rule_tag_add() inside a RW transaction would be better.
+static int tag_names_default(void)
+{
+ uint8_t key_tb_str[] = "\0tagBits";
+ knot_db_val_t key = { .data = key_tb_str, .len = sizeof(key_tb_str) };
+ knot_db_val_t val;
+ // Check what's in there.
+ int ret = ruledb_op(read, &key, &val, 1);
+ if (ret == 0 && !kr_fails_assert(val.data && val.len == sizeof(kr_rule_tags_t)))
+ return kr_ok(); // it's probably OK
+ if (ret != kr_error(ENOENT))
+ return kr_error(ret);
+ kr_rule_tags_t empty = 0;
+ val.data = ∅
+ val.len = sizeof(empty);
+ return ruledb_op(write, &key, &val, 1);
+}
+
+int kr_rule_tag_add(const char *tag, kr_rule_tags_t *tagset)
+{
+ // Construct the DB key.
+ const uint8_t key_prefix[] = "\0tag_";
+ knot_db_val_t key;
+ knot_db_val_t val;
+ const size_t tag_len = strlen(tag);
+ key.len = sizeof(key_prefix) + tag_len;
+ uint8_t key_buf[key.len];
+ key.data = key_buf;
+ memcpy(key_buf, key_prefix, sizeof(key_prefix));
+ memcpy(key_buf + sizeof(key_prefix), tag, tag_len);
+
+ int ret = ruledb_op(read, &key, &val, 1);
+ if (ret == 0) { // tag exists already
+ uint8_t *tindex_p = val.data;
+ static_assert(KR_RULE_TAGS_CAP < (1 << 8 * sizeof(*tindex_p)),
+ "bad combination of constants");
+ if (kr_fails_assert(val.data && val.len == 1
+ && *tindex_p < KR_RULE_TAGS_CAP)) {
+ kr_log_error(RULES, "ERROR: invalid length: %d\n", (int)val.len);
+ return kr_error(EILSEQ);
+ }
+ *tagset |= (1 << *tindex_p);
+ return kr_ok();
+ } else if (ret != kr_error(ENOENT)) {
+ return ret;
+ }
+
+ // We need to add it as a new tag. First find the bitmap of named tags.
+ uint8_t key_tb_str[] = "\0tagBits";
+ knot_db_val_t key_tb = { .data = key_tb_str, .len = sizeof(key_tb_str) };
+ ret = ruledb_op(read, &key_tb, &val, 1);
+ if (ret != 0)
+ return kr_error(ret);
+ if (kr_fails_assert(val.data && val.len == sizeof(kr_rule_tags_t))) {
+ kr_log_error(RULES, "ERROR: invalid length: %d\n", (int)val.len);
+ return kr_error(EILSEQ);
+ }
+ kr_rule_tags_t bmp;
+ memcpy(&bmp, val.data, sizeof(bmp));
+ // Find a free index.
+ static_assert(sizeof(long long) >= sizeof(bmp), "bad combination of constants");
+ int ix = ffsll(~bmp) - 1;
+ if (ix < 0 || ix >= 8 * sizeof(bmp))
+ return kr_error(E2BIG);
+ const kr_rule_tags_t tag_new = 1 << ix;
+ kr_require((tag_new & bmp) == 0);
+
+ // Update the mappings
+ bmp |= tag_new;
+ val.data = &bmp;
+ val.len = sizeof(bmp);
+ ret = ruledb_op(write, &key_tb, &val, 1);
+ if (ret != 0)
+ return kr_error(ret);
+ uint8_t ix_8t = ix;
+ val.data = &ix_8t;
+ val.len = sizeof(ix_8t);
+ ret = ruledb_op(write, &key, &val, 1); // key remained correct
+ if (ret != 0)
+ return kr_error(ret);
+ *tagset |= tag_new;
+ return kr_ok();
+}
+
+
//TODO later, maybe. ATM it would be cumbersome to avoid void* arithmetics.
#pragma GCC diagnostic ignored "-Wpointer-arith"
@@ -95,6 +182,9 @@ int kr_rules_init(void)
if (ret != 0) goto failure;
kr_require(the_rules->db);
+ ret = tag_names_default();
+ if (ret != 0) goto failure;
+
ret = rules_defaults_insert();
if (ret != 0) goto failure;