diff --git a/src/common/config.c b/src/common/config.c index ef5df7925..f750dc56a 100644 --- a/src/common/config.c +++ b/src/common/config.c @@ -62,6 +62,12 @@ struct nla_policy joolnl_pool4_entry_policy[JNLAP4_COUNT] = { [JNLAP4_PORT_MAX] = { .type = NLA_U16 }, }; +struct nla_policy joolnl_p4block_policy[JNLAPB_COUNT] = { + [JNLAPB_ADDR] = JOOLNL_ADDR4_POLICY, + [JNLAPB_PORT_MIN] = { .type = NLA_U16 }, + [JNLAPB_PORT_MAX] = { .type = NLA_U16 }, +}; + struct nla_policy joolnl_bib_entry_policy[JNLAB_COUNT] = { [JNLAB_SRC6] = { .type = NLA_NESTED }, [JNLAB_SRC4] = { .type = NLA_NESTED }, diff --git a/src/common/config.h b/src/common/config.h index bc7dc6b6b..f90517b7d 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -50,6 +50,10 @@ enum joolnl_operation { JNLOP_POOL4_RM, JNLOP_POOL4_FLUSH, + JNLOP_P4BLOCK_FOREACH, + JNLOP_P4BLOCK_ADD, + JNLOP_P4BLOCK_RM, + JNLOP_BIB_FOREACH, JNLOP_BIB_ADD, JNLOP_BIB_RM, @@ -178,6 +182,16 @@ enum joolnl_attr_pool4 { extern struct nla_policy joolnl_pool4_entry_policy[JNLAP4_COUNT]; +enum joolnl_attr_p4block { + JNLAPB_ADDR = 1, + JNLAPB_PORT_MIN, + JNLAPB_PORT_MAX, + JNLAPB_COUNT, +#define JNLAPB_MAX (JNLAPB_COUNT - 1) +}; + +extern struct nla_policy joolnl_p4block_policy[JNLAPB_COUNT]; + enum joolnl_attr_bib { JNLAB_SRC6 = 1, JNLAB_SRC4, diff --git a/src/common/types.h b/src/common/types.h index 4962ee826..7f8b8a37f 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -203,6 +203,11 @@ struct pool4_entry { struct ipv4_range range; }; +struct p4block { + struct in_addr addr; + struct port_range ports; +}; + /* * A mask that dictates which IPv4 transport address is being used to mask a * given IPv6 (transport) client. diff --git a/src/mod/common/Kbuild b/src/mod/common/Kbuild index 6ab829804..a71b98cce 100644 --- a/src/mod/common/Kbuild +++ b/src/mod/common/Kbuild @@ -3,7 +3,6 @@ ccflags-y := -I$(src)/../.. obj-m += jool_common.o - jool_common-objs += rfc7915/4to6.o jool_common-objs += rfc7915/6to4.o jool_common-objs += rfc7915/common.o @@ -37,7 +36,6 @@ jool_common-objs += wrapper-config.o jool_common-objs += wrapper-global.o jool_common-objs += wrapper-types.o jool_common-objs += xlator.o - jool_common-objs += steps/send_packet.o jool_common-objs += nl/address.o @@ -52,6 +50,7 @@ jool_common-objs += nl/global.o jool_common-objs += nl/instance.o jool_common-objs += nl/joold.o jool_common-objs += nl/nl_common.o +jool_common-objs += nl/p4block.o jool_common-objs += nl/pool4.o jool_common-objs += nl/session.o jool_common-objs += nl/stats.o @@ -66,6 +65,7 @@ jool_common-objs += db/rfc6791v6.o jool_common-objs += db/pool4/empty.o jool_common-objs += db/pool4/db.o jool_common-objs += db/pool4/rfc6056.o +jool_common-objs += db/pool4-v2/block.o jool_common-objs += db/bib/db.o jool_common-objs += db/bib/entry.o diff --git a/src/mod/common/db/pool4-v2/block.c b/src/mod/common/db/pool4-v2/block.c new file mode 100644 index 000000000..af22ff9ae --- /dev/null +++ b/src/mod/common/db/pool4-v2/block.c @@ -0,0 +1,286 @@ +#include "mod/common/db/pool4-v2/block.h" + +#include +#include +#include +#include +#include +#include + +#include "mod/common/address.h" +#include "mod/common/log.h" + +struct block { + struct p4block blk; + + struct in6_addr assigned_addr6; /* Currently assigned client */ + u64 last_used_time; + + bool is_assigned; + union { + /* is_assigned false */ + struct list_head list; /* For @idle_blocks */ + /* is_assigned true */ + struct hlist_node htable; /* For @assignments */ + } hook; +}; + +#define HTABLE_BITS 8 + +struct p4blocks { + /* Length of @blocks and @assignments */ + size_t total_blocks; + /* Extract from @blocks which haven't yet assigned to any IPv6 addresses */ + struct list_head idle_blocks; + /* + * Extract from @blocks which have been assigned IPv6 addresses, indexed by IPv6 + * address. + */ + DECLARE_HASHTABLE(assignments, HTABLE_BITS); + + spinlock_t lock; + struct kref refs; +}; + +struct p4blocks *p4block_init(void) +{ + struct p4blocks *result; + + result = kmalloc(sizeof(struct p4blocks), GFP_KERNEL); + if (!result) + return NULL; + + result->total_blocks = 0; + INIT_LIST_HEAD(&result->idle_blocks); + hash_init(result->assignments); + spin_lock_init(&result->lock); + kref_init(&result->refs); + + return result; +} + +void p4block_get(struct p4blocks *blocks) +{ + kref_get(&blocks->refs); +} + +static void p4block_release(struct kref *refs) +{ + struct p4blocks *blocks; + struct block *blk; + struct hlist_node *tmp; + size_t b; + + blocks = container_of(refs, struct p4blocks, refs); + + while (!list_empty(&blocks->idle_blocks)) { + blk = list_first_entry(&blocks->idle_blocks, struct block, + hook.list); + list_del(&blk->hook.list); + kfree(blk); + } + + hash_for_each_safe(blocks->assignments, b, tmp, blk, hook.htable) { + hash_del(&blk->hook.htable); + kfree(blk); + } + + kfree(blocks); +} + +void p4block_put(struct p4blocks *blocks) +{ + kref_put(&blocks->refs, p4block_release); +} + +int p4block_add(struct p4blocks *blocks, struct p4block *addend) +{ + struct block *node; + + node = kmalloc(sizeof(struct block), GFP_KERNEL); + if (!node) + return -ENOMEM; + node->blk = *addend; + node->is_assigned = false; + + spin_lock_bh(&blocks->lock); + list_add_tail(&node->hook.list, &blocks->idle_blocks); + spin_unlock_bh(&blocks->lock); + + return 0; +} + +static bool block_equals(struct block *a, struct p4block *b) +{ + return addr4_equals(&a->blk.addr, &b->addr) + && (a->blk.ports.min == b->ports.min) + && (a->blk.ports.max == b->ports.max); +} + +int p4block_rm(struct p4blocks *blocks, struct p4block *subtrahend) +{ + size_t b; + struct block *node; + + spin_lock_bh(&blocks->lock); + + list_for_each_entry(node, &blocks->idle_blocks, hook.list) { + if (block_equals(node, subtrahend)) { + list_del(&node->hook.list); + goto success; + } + } + + hash_for_each(blocks->assignments, b, node, hook.htable) { + if (block_equals(node, subtrahend)) { + hash_del(&node->hook.htable); + goto success; + } + } + + spin_unlock_bh(&blocks->lock); + return -ESRCH; + +success: + spin_unlock_bh(&blocks->lock); + kfree(node); + return 0; +} + +void p4block_print(struct p4blocks *blocks, const char *prefix) +{ + size_t b; + struct block *node; + + pr_info("%s: {\n", prefix ? prefix : "Blocks"); + list_for_each_entry(node, &blocks->idle_blocks, hook.list) { + pr_info(" %pI4c:%u-%u\n", &node->blk.addr, node->blk.ports.min, + node->blk.ports.max); + } + hash_for_each(blocks->assignments, b, node, hook.htable) { + pr_info(" %pI4c:%u-%u (assigned to %pI6c)\n", &node->blk.addr, + node->blk.ports.min, node->blk.ports.max, + &node->assigned_addr6); + } + pr_info("}\n"); +} + +static u16 hash_addr6(const struct in6_addr *addr6) +{ + __u32 q3; + __u32 q7; + + q3 = be16_to_cpu(addr6->s6_addr16[3]); + q7 = be16_to_cpu(addr6->s6_addr16[7]); + + return hash_32((q3 << 16) | q7, HTABLE_BITS); +} + +static struct block *get_next_unused_block(struct p4blocks *blocks) +{ + if (list_empty(&blocks->idle_blocks)) + return NULL; + return list_first_entry(&blocks->idle_blocks, struct block, hook.list); +} + +int p4block_find(struct p4blocks *blocks, struct in6_addr *client, + struct p4block *result) +{ + struct block *db_node; + u64 now; + __u16 hash; + + now = get_jiffies_64(); + hash = hash_addr6(client); + + spin_lock_bh(&blocks->lock); + + /* If already assigned, return assigned block */ + hlist_for_each_entry(db_node, &blocks->assignments[hash], hook.htable) + if (addr6_equals(&db_node->assigned_addr6, client)) + goto success; + + db_node = get_next_unused_block(blocks); + if (db_node == NULL) { + spin_unlock_bh(&blocks->lock); + log_warn_once( + "Client %pI6c needs a pool4 block, but I already ran out.", + client + ); + return -ESRCH; + } + + list_del(&db_node->hook.list); + hlist_add_head(&db_node->hook.htable, &blocks->assignments[hash]); + db_node->assigned_addr6 = *client; + db_node->is_assigned = true; + /* Fall through */ + +success: + db_node->last_used_time = now; + *result = db_node->blk; + spin_unlock_bh(&blocks->lock); + return 0; +} + +bool addr4_matches_blk(struct p4block const *blk, + struct ipv4_transport_addr const *addr4) +{ + return addr4_equals(&blk->addr, &addr4->l3) + && (blk->ports.min <= addr4->l4) + && (addr4->l4 <= blk->ports.max); +} + +bool p4block_contains(struct p4blocks *blocks, + struct ipv4_transport_addr const *addr) +{ + size_t b; + struct block *node; + + spin_lock_bh(&blocks->lock); + + list_for_each_entry(node, &blocks->idle_blocks, hook.list) + if (addr4_matches_blk(&node->blk, addr)) + goto yes; + hash_for_each(blocks->assignments, b, node, hook.htable) + if (addr4_matches_blk(&node->blk, addr)) + goto yes; + + spin_unlock_bh(&blocks->lock); + return false; + +yes: + spin_unlock_bh(&blocks->lock); + return true; +} + +void p4block_expire(struct p4blocks *blocks, u64 time_limit) +{ + u64 now; + struct block *blk; + struct hlist_node *tmp; + size_t b; + + now = get_jiffies_64(); + + spin_lock_bh(&blocks->lock); + hash_for_each_safe(blocks->assignments, b, tmp, blk, hook.htable) { + if (now - blk->last_used_time > time_limit) { + blk->is_assigned = false; + hash_del(&blk->hook.htable); + list_add_tail(&blk->hook.list, &blocks->idle_blocks); + } + } + spin_unlock_bh(&blocks->lock); +} + +/* TODO fix unit tests and remove this */ +void p4block_cheat(struct p4blocks *blocks) +{ + size_t b; + struct block *node; + + hash_for_each(blocks->assignments, b, node, hook.htable) { + node->last_used_time -= 100000; + } +} diff --git a/src/mod/common/db/pool4-v2/block.h b/src/mod/common/db/pool4-v2/block.h new file mode 100644 index 000000000..fb27d4074 --- /dev/null +++ b/src/mod/common/db/pool4-v2/block.h @@ -0,0 +1,26 @@ +#ifndef SRC_MOD_COMMON_DB_POOL4_V2_BLOCK_H_ +#define SRC_MOD_COMMON_DB_POOL4_V2_BLOCK_H_ + +#include "common/types.h" + +struct p4blocks; + +/* Constructors, destructors */ +struct p4blocks *p4block_init(void); +void p4block_get(struct p4blocks *); +void p4block_put(struct p4blocks *); + +/* Userspace client */ +int p4block_add(struct p4blocks *, struct p4block *); +int p4block_rm(struct p4blocks *, struct p4block *); +void p4block_print(struct p4blocks *, const char *); + +/* Translation */ +int p4block_find(struct p4blocks *, struct in6_addr *, struct p4block *); +bool p4block_contains(struct p4blocks *, struct ipv4_transport_addr const *); +void p4block_expire(struct p4blocks *, u64 time_limit); + +/* Testing */ +void p4block_cheat(struct p4blocks *blocks); + +#endif /* SRC_MOD_COMMON_DB_POOL4_V2_BLOCK_H_ */ diff --git a/src/mod/common/db/pool4/db.c b/src/mod/common/db/pool4/db.c index 809cb8f8e..3090178fb 100644 --- a/src/mod/common/db/pool4/db.c +++ b/src/mod/common/db/pool4/db.c @@ -10,6 +10,7 @@ #include "mod/common/db/rbtree.h" #include "mod/common/db/pool4/empty.h" #include "mod/common/db/pool4/rfc6056.h" +#include "mod/common/db/pool4-v2/block.h" /* * pool4 (struct pool4) is made out of two tree groups (struct pool4_trees). @@ -1073,6 +1074,54 @@ static verdict find_empty(struct xlation *state, unsigned int offset, return VERDICT_CONTINUE; } +enum jool_stat_id __mask_domain_find_block(struct p4blocks *blocks, + struct in6_addr *src, struct mask_domain **out) +{ + struct mask_domain *result; + struct ipv4_range *range; + struct p4block block; + __u16 starting_port; + + result = __wkmalloc("mask_domain", + sizeof(struct mask_domain) + sizeof(struct ipv4_range), + GFP_ATOMIC); + if (!result) + return JSTAT_ENOMEM; + range = (struct ipv4_range *) (result + 1); + + if (p4block_find(blocks, src, &block) != 0) { + __wkfree("mask_domain", result); + return JSTAT_UNKNOWN; // TODO fix stat + } + + result->pool_mark = 0; + result->taddr_count = block.ports.max - block.ports.min + 1; + result->taddr_counter = 0; + result->max_iterations = 0; + result->range_count = 1; + result->current_range = range; + get_random_bytes(&starting_port, sizeof(starting_port)); + result->current_port = block.ports.min + starting_port % result->taddr_count; + result->dynamic = false; + range->prefix.addr = block.addr; + range->prefix.len = 32; + range->ports.min = block.ports.min; + range->ports.max = block.ports.max; + + *out = result; + return JSTAT_SUCCESS; +} + +verdict mask_domain_find_block(struct xlation *state, struct mask_domain **out) +{ + enum jool_stat_id stat; + stat = __mask_domain_find_block(state->jool.nat64.blocks, + &pkt_ip6_hdr(&state->in)->saddr, out); + if (stat != JSTAT_SUCCESS) + return drop(state, stat); + return VERDICT_CONTINUE; +} + verdict mask_domain_find(struct xlation *state, struct mask_domain **out) { struct pool4 *pool; diff --git a/src/mod/common/db/pool4/db.h b/src/mod/common/db/pool4/db.h index 6e735c95c..b1b631be0 100644 --- a/src/mod/common/db/pool4/db.h +++ b/src/mod/common/db/pool4/db.h @@ -44,6 +44,8 @@ int pool4db_foreach_sample(struct pool4 *pool, l4_protocol proto, struct mask_domain; +verdict mask_domain_find_block(struct xlation *state, struct mask_domain **out); + verdict mask_domain_find(struct xlation *state, struct mask_domain **out); void mask_domain_put(struct mask_domain *masks); int mask_domain_next(struct mask_domain *masks, diff --git a/src/mod/common/nl/attribute.c b/src/mod/common/nl/attribute.c index dd20f6025..0b14bd348 100644 --- a/src/mod/common/nl/attribute.c +++ b/src/mod/common/nl/attribute.c @@ -300,6 +300,25 @@ int jnla_get_pool4(struct nlattr *attr, char const *name, return 0; } +int jnla_get_p4block(struct nlattr *attr, char const *name, struct p4block *blk) +{ + struct nlattr *attrs[JNLAPB_COUNT]; + int error; + + error = validate_null(attr, name); + if (error) + return error; + + error = jnla_parse_nested(attrs, JNLAPB_MAX, attr, + joolnl_p4block_policy, name); + if (error) + return error; + + blk->ports.min = nla_get_u16(attrs[JNLAPB_PORT_MIN]); + blk->ports.max = nla_get_u16(attrs[JNLAPB_PORT_MAX]); + return jnla_get_addr4(attrs[JNLAPB_ADDR], "IPv4 address", &blk->addr); +} + int jnla_get_bib(struct nlattr *attr, char const *name, struct bib_entry *entry) { struct nlattr *attrs[JNLAB_COUNT]; @@ -684,6 +703,28 @@ int jnla_put_pool4(struct sk_buff *skb, int attrtype, return 0; } +int jnla_put_p4block(struct sk_buff *skb, int attrtype, + struct p4block const *entry) +{ + struct nlattr *root; + int error; + + root = nla_nest_start(skb, attrtype); + if (!root) + return -EMSGSIZE; + + error = jnla_put_addr4(skb, JNLAPB_ADDR, &entry->addr) + || nla_put_u16(skb, JNLAPB_PORT_MIN, entry->ports.min) + || nla_put_u16(skb, JNLAPB_PORT_MAX, entry->ports.max); + if (error) { + nla_nest_cancel(skb, root); + return error; + } + + nla_nest_end(skb, root); + return 0; +} + int jnla_put_bib(struct sk_buff *skb, int attrtype, struct bib_entry const *bib) { struct nlattr *root; diff --git a/src/mod/common/nl/attribute.h b/src/mod/common/nl/attribute.h index 6bade7452..5ab22f8af 100644 --- a/src/mod/common/nl/attribute.h +++ b/src/mod/common/nl/attribute.h @@ -19,6 +19,7 @@ int jnla_get_taddr6(struct nlattr *attr, char const *name, struct ipv6_transport int jnla_get_taddr4(struct nlattr *attr, char const *name, struct ipv4_transport_addr *out); int jnla_get_eam(struct nlattr *attr, char const *name, struct eamt_entry *eam); int jnla_get_pool4(struct nlattr *attr, char const *name, struct pool4_entry *entry); +int jnla_get_p4block(struct nlattr *attr, char const *name, struct p4block *entry); int jnla_get_bib(struct nlattr *attr, char const *name, struct bib_entry *entry); int jnla_get_session(struct nlattr *attr, char const *name, struct bib_config *config, struct session_entry *entry); int jnla_get_plateaus(struct nlattr *attr, struct mtu_plateaus *out); @@ -32,6 +33,7 @@ int jnla_put_taddr6(struct sk_buff *skb, int attrtype, struct ipv6_transport_add int jnla_put_taddr4(struct sk_buff *skb, int attrtype, struct ipv4_transport_addr const *prefix); int jnla_put_eam(struct sk_buff *skb, int attrtype, struct eamt_entry const *eam); int jnla_put_pool4(struct sk_buff *skb, int attrtype, struct pool4_entry const *bib); +int jnla_put_p4block(struct sk_buff *skb, int attrtype, struct p4block const *entry); int jnla_put_bib(struct sk_buff *skb, int attrtype, struct bib_entry const *bib); int jnla_put_session(struct sk_buff *skb, int attrtype, struct session_entry const *entry); int jnla_put_plateaus(struct sk_buff *skb, int attrtype, struct mtu_plateaus const *plateaus); diff --git a/src/mod/common/nl/bib.c b/src/mod/common/nl/bib.c index fc754aff2..7d8f8203d 100644 --- a/src/mod/common/nl/bib.c +++ b/src/mod/common/nl/bib.c @@ -5,7 +5,7 @@ #include "mod/common/nl/attribute.h" #include "mod/common/nl/nl_common.h" #include "mod/common/nl/nl_core.h" -#include "mod/common/db/pool4/db.h" +#include "mod/common/db/pool4-v2/block.h" #include "mod/common/db/bib/db.h" static int serialize_bib_entry(struct bib_entry const *entry, void *arg) @@ -82,8 +82,9 @@ int handle_bib_add(struct sk_buff *skb, struct genl_info *info) if (error) goto revert_start; - if (!pool4db_contains(jool.nat64.pool4, jool.ns, new.l4_proto, &new.addr4)) { - log_err("The transport address '%pI4#%u' does not belong to pool4.\n" +// if (!pool4db_contains(jool.nat64.pool4, jool.ns, new.l4_proto, &new.addr4)) { + if (!p4block_contains(jool.nat64.blocks, &new.addr4)) { + log_err("The transport address '%pI4#%u' does not belong to p4block.\n" "Please add it there first.", &new.addr4.l3, new.addr4.l4); error = -EINVAL; diff --git a/src/mod/common/nl/nl_handler.c b/src/mod/common/nl/nl_handler.c index 95e46f464..b4fa16b64 100644 --- a/src/mod/common/nl/nl_handler.c +++ b/src/mod/common/nl/nl_handler.c @@ -18,6 +18,7 @@ #include "mod/common/nl/joold.h" #include "mod/common/nl/nl_common.h" #include "mod/common/nl/nl_core.h" +#include "mod/common/nl/p4block.h" #include "mod/common/nl/pool4.h" #include "mod/common/nl/session.h" #include "mod/common/nl/stats.h" @@ -146,6 +147,18 @@ static const struct genl_ops ops[] = { .cmd = JNLOP_POOL4_FLUSH, .doit = handle_pool4_flush, JOOL_POLICY + }, { + .cmd = JNLOP_P4BLOCK_FOREACH, + .doit = handle_p4block_foreach, + JOOL_POLICY + }, { + .cmd = JNLOP_P4BLOCK_ADD, + .doit = handle_p4block_add, + JOOL_POLICY + }, { + .cmd = JNLOP_P4BLOCK_RM, + .doit = handle_p4block_rm, + JOOL_POLICY }, { .cmd = JNLOP_BIB_FOREACH, .doit = handle_bib_foreach, diff --git a/src/mod/common/nl/p4block.c b/src/mod/common/nl/p4block.c new file mode 100644 index 000000000..76cd722c3 --- /dev/null +++ b/src/mod/common/nl/p4block.c @@ -0,0 +1,72 @@ +#include "mod/common/nl/p4block.h" + +#include "mod/common/log.h" +#include "mod/common/xlator.h" +#include "mod/common/nl/attribute.h" +#include "mod/common/nl/nl_common.h" +#include "mod/common/nl/nl_core.h" +#include "mod/common/db/pool4-v2/block.h" + +int handle_p4block_foreach(struct sk_buff *skb, struct genl_info *info) +{ + struct xlator jool; + int error; + + error = request_handle_start(info, XT_NAT64, &jool, true); + if (error) + return jresponse_send_simple(NULL, info, error); + + __log_debug(&jool, "Printing p4blocks on the log."); + + p4block_print(jool.nat64.blocks, NULL); + + error = jresponse_send_simple(&jool, info, error); + request_handle_end(&jool); + return error; +} + +int handle_p4block_add(struct sk_buff *skb, struct genl_info *info) +{ + struct xlator jool; + struct p4block addend; + int error; + + error = request_handle_start(info, XT_NAT64, &jool, true); + if (error) + return jresponse_send_simple(NULL, info, error); + + __log_debug(&jool, "Adding p4block entry."); + + error = jnla_get_p4block(info->attrs[JNLAR_OPERAND], "Operand", &addend); + if (error) + goto revert_start; + + error = p4block_add(jool.nat64.blocks, &addend); +revert_start: + error = jresponse_send_simple(&jool, info, error); + request_handle_end(&jool); + return error; +} + +int handle_p4block_rm(struct sk_buff *skb, struct genl_info *info) +{ + struct xlator jool; + struct p4block subtrahend; + int error; + + error = request_handle_start(info, XT_NAT64, &jool, true); + if (error) + return jresponse_send_simple(NULL, info, error); + + __log_debug(&jool, "Removing p4block entry."); + + error = jnla_get_p4block(info->attrs[JNLAR_OPERAND], "Operand", &subtrahend); + if (error) + goto revert_start; + + error = p4block_rm(jool.nat64.blocks, &subtrahend); +revert_start: + error = jresponse_send_simple(&jool, info, error); + request_handle_end(&jool); + return error; +} diff --git a/src/mod/common/nl/p4block.h b/src/mod/common/nl/p4block.h new file mode 100644 index 000000000..bd62f9adf --- /dev/null +++ b/src/mod/common/nl/p4block.h @@ -0,0 +1,10 @@ +#ifndef SRC_MOD_COMMON_NL_P4BLOCK_H_ +#define SRC_MOD_COMMON_NL_P4BLOCK_H_ + +#include + +int handle_p4block_foreach(struct sk_buff *skb, struct genl_info *info); +int handle_p4block_add(struct sk_buff *skb, struct genl_info *info); +int handle_p4block_rm(struct sk_buff *skb, struct genl_info *info); + +#endif /* SRC_MOD_COMMON_NL_P4BLOCK_H_ */ diff --git a/src/mod/common/steps/filtering_and_updating.c b/src/mod/common/steps/filtering_and_updating.c index 1392189c1..b5d9d86a8 100644 --- a/src/mod/common/steps/filtering_and_updating.c +++ b/src/mod/common/steps/filtering_and_updating.c @@ -14,7 +14,7 @@ #include "mod/common/stats.h" #include "mod/common/rfc7915/6to4.h" #include "mod/common/joold.h" -#include "mod/common/db/pool4/db.h" +#include "mod/common/db/pool4-v2/block.h" #include "mod/common/db/bib/db.h" enum session_fate tcp_est_expire_cb(struct session_entry *session, void *arg) @@ -132,7 +132,7 @@ static verdict ipv6_simple(struct xlation *state) if (xlat_dst_6to4(state, &dst4)) return drop(state, JSTAT_UNTRANSLATABLE_DST6); - result = mask_domain_find(state, &masks); + result = mask_domain_find_block(state, &masks); if (result != VERDICT_CONTINUE) { log_debug(state, "There is no mask domain mapped to mark %u.", state->in.skb->mark); @@ -449,7 +449,7 @@ static verdict ipv6_tcp(struct xlation *state) if (xlat_dst_6to4(state, &dst4)) return drop(state, JSTAT_UNTRANSLATABLE_DST6); - result = mask_domain_find(state, &masks); + result = mask_domain_find_block(state, &masks); if (result != VERDICT_CONTINUE) { log_debug(state, "There is no mask domain mapped to mark %u.", state->in.skb->mark); @@ -523,9 +523,11 @@ verdict filtering_and_updating(struct xlation *state) break; case L3PROTO_IPV4: /* Get rid of unexpected packets */ - if (!pool4db_contains(state->jool.nat64.pool4, state->jool.ns, - in->tuple.l4_proto, &in->tuple.dst.addr4)) { - log_debug(state, "Packet does not belong to pool4."); +// if (!pool4db_contains(state->jool.nat64.pool4, state->jool.ns, +// in->tuple.l4_proto, &in->tuple.dst.addr4)) { + if (!p4block_contains(state->jool.nat64.blocks, + &in->tuple.dst.addr4)) { + log_debug(state, "Packet does not belong to p4block."); return untranslatable(state, JSTAT_POOL4_MISMATCH); } diff --git a/src/mod/common/steps/handling_hairpinning_nat64.c b/src/mod/common/steps/handling_hairpinning_nat64.c index 09ac6217a..9a53735a4 100644 --- a/src/mod/common/steps/handling_hairpinning_nat64.c +++ b/src/mod/common/steps/handling_hairpinning_nat64.c @@ -5,7 +5,7 @@ #include "mod/common/steps/send_packet.h" #include "mod/common/steps/compute_outgoing_tuple.h" #include "mod/common/steps/filtering_and_updating.h" -#include "mod/common/db/pool4/db.h" +#include "mod/common/db/pool4-v2/block.h" /** @@ -28,8 +28,10 @@ bool is_hairpin_nat64(struct xlation *state) * for its node. It might take a miracle for these packets to exist, * but hey, why the hell not. */ - return pool4db_contains(state->jool.nat64.pool4, state->jool.ns, - state->out.tuple.l4_proto, &state->out.tuple.dst.addr4); +// return pool4db_contains(state->jool.nat64.pool4, state->jool.ns, +// state->out.tuple.l4_proto, &state->out.tuple.dst.addr4); + return p4block_contains(state->jool.nat64.blocks, + &state->out.tuple.dst.addr4); } /** diff --git a/src/mod/common/xlator.c b/src/mod/common/xlator.c index 12c782e67..9b5df461d 100644 --- a/src/mod/common/xlator.c +++ b/src/mod/common/xlator.c @@ -16,6 +16,7 @@ #include "mod/common/db/denylist4.h" #include "mod/common/db/eam.h" #include "mod/common/db/pool4/db.h" +#include "mod/common/db/pool4-v2/block.h" #include "mod/common/db/bib/db.h" #include "mod/common/steps/handling_hairpinning_nat64.h" #include "mod/common/steps/handling_hairpinning_siit.h" @@ -142,6 +143,7 @@ static void xlator_get(struct xlator *jool) break; case XT_NAT64: pool4db_get(jool->nat64.pool4); + p4block_get(jool->nat64.blocks); bib_get(jool->nat64.bib); joold_get(jool->nat64.joold); break; @@ -320,6 +322,9 @@ static int init_nat64(struct xlator *jool, struct ipv6_prefix *pool6) jool->nat64.pool4 = pool4db_alloc(); if (!jool->nat64.pool4) goto pool4_fail; + jool->nat64.blocks = p4block_init(); + if (!jool->nat64.blocks) + goto p4block_fail; jool->nat64.bib = bib_alloc(); if (!jool->nat64.bib) goto bib_fail; @@ -334,6 +339,8 @@ static int init_nat64(struct xlator *jool, struct ipv6_prefix *pool6) joold_fail: bib_put(jool->nat64.bib); bib_fail: + p4block_put(jool->nat64.blocks); +p4block_fail: pool4db_put(jool->nat64.pool4); pool4_fail: jstat_put(jool->stats); @@ -633,8 +640,9 @@ static int check_bib(struct bib_entry const *bib, void *_arg) { struct check_bib_arg *arg = _arg; - if (!pool4db_contains(arg->jool->nat64.pool4, arg->jool->ns, - bib->l4_proto, &bib->addr4)) { +// if (!pool4db_contains(arg->jool->nat64.pool4, arg->jool->ns, +// bib->l4_proto, &bib->addr4)) { + if (!p4block_contains(arg->jool->nat64.blocks, &bib->addr4)) { arg->badbib = *bib; return -EINVAL; } @@ -904,6 +912,7 @@ void xlator_put(struct xlator *jool) * have to leave those modules around. */ pool4db_put(jool->nat64.pool4); + p4block_put(jool->nat64.blocks); if (jool->nat64.bib) bib_put(jool->nat64.bib); if (jool->nat64.joold) diff --git a/src/mod/common/xlator.h b/src/mod/common/xlator.h index 37f451cc8..f8b7cc238 100644 --- a/src/mod/common/xlator.h +++ b/src/mod/common/xlator.h @@ -40,6 +40,7 @@ struct xlator { } siit; struct { struct pool4 *pool4; + struct p4blocks *blocks; struct bib *bib; struct joold_queue *joold; } nat64; diff --git a/src/usr/argp/Makefile.am b/src/usr/argp/Makefile.am index 290f28fae..dd1335544 100644 --- a/src/usr/argp/Makefile.am +++ b/src/usr/argp/Makefile.am @@ -18,6 +18,7 @@ libjoolargp_la_SOURCES = \ wargp/global.c wargp/global.h \ wargp/instance.c wargp/instance.h \ wargp/joold.c wargp/joold.h \ + wargp/p4block.c wargp/p4block.h \ wargp/pool4.c wargp/pool4.h \ wargp/session.c wargp/session.h \ wargp/stats.c wargp/stats.h diff --git a/src/usr/argp/main.c b/src/usr/argp/main.c index 744a6df07..6b0794be0 100644 --- a/src/usr/argp/main.c +++ b/src/usr/argp/main.c @@ -25,6 +25,7 @@ #include "usr/argp/wargp/global.h" #include "usr/argp/wargp/instance.h" #include "usr/argp/wargp/joold.h" +#include "usr/argp/wargp/p4block.h" #include "usr/argp/wargp/pool4.h" #include "usr/argp/wargp/session.h" #include "usr/argp/wargp/stats.h" @@ -201,6 +202,26 @@ struct cmd_option pool4_ops[] = { { 0 }, }; +struct cmd_option p4block_ops[] = { + { + .label = DISPLAY, + .xt = XT_NAT64, + .handler = handle_p4block_display, + .handle_autocomplete = autocomplete_p4block_display, + }, { + .label = ADD, + .xt = XT_NAT64, + .handler = handle_p4block_add, + .handle_autocomplete = autocomplete_p4block_add, + }, { + .label = REMOVE, + .xt = XT_NAT64, + .handler = handle_p4block_remove, + .handle_autocomplete = autocomplete_p4block_remove, + }, + { 0 }, +}; + static struct cmd_option bib_ops[] = { { .label = DISPLAY, @@ -284,6 +305,10 @@ struct cmd_option tree[] = { .label = "pool4", .xt = XT_NAT64, .children = pool4_ops, + }, { + .label = "p4block", + .xt = XT_NAT64, + .children = p4block_ops, }, { .label = "bib", .xt = XT_NAT64, diff --git a/src/usr/argp/wargp/p4block.c b/src/usr/argp/wargp/p4block.c new file mode 100644 index 000000000..7bf0ecf19 --- /dev/null +++ b/src/usr/argp/wargp/p4block.c @@ -0,0 +1,133 @@ +#include "usr/argp/wargp/p4block.h" + +#include "usr/argp/log.h" +#include "usr/argp/wargp.h" +#include "usr/argp/xlator_type.h" +#include "usr/nl/core.h" +#include "usr/nl/p4block.h" +#include "usr/util/str_utils.h" + +#define P4BLOCK_SYNTAX ":-" + +int handle_p4block_display(char *iname, int argc, char **argv, void const *arg) +{ + struct joolnl_socket sk; + struct jool_result result; + + result = joolnl_setup(&sk, xt_get()); + if (result.error) + return pr_result(&result); + + result = joolnl_p4block_foreach(&sk, iname); + + joolnl_teardown(&sk); + + if (result.error) + return pr_result(&result); + + printf("Done; see dmesg.\n"); + return 0; +} + +void autocomplete_p4block_display(void const *args) +{ + /* No code */ +} + +struct update_args { + struct p4block blk; +}; + +static int parse_p4block_column(void *void_field, int key, char *str) +{ + struct p4block *blk = void_field; + struct jool_result result; + char *colon, *dash; + + colon = strchr(str, ':'); + if (colon == NULL) + goto parse_failure; + + *colon = '\0'; + result = str_to_addr4(str, &blk->addr); + if (result.error) + return pr_result(&result); + *colon = ':'; + + str = colon + 1; + dash = strchr(str, '-'); + if (dash == NULL) + goto parse_failure; + + *dash = '\0'; + result = str_to_u16(str, &blk->ports.min); + if (result.error) + return pr_result(&result); + *dash = '-'; + + str = dash + 1; + result = str_to_u16(str, &blk->ports.max); + return pr_result(&result); + +parse_failure: + result = result_from_error(-EINVAL, "Unrecognized syntax; please use " + P4BLOCK_SYNTAX ".\n"); + return pr_result(&result); +} + +struct wargp_type wt_p4block = { + .argument = P4BLOCK_SYNTAX, + .parse = parse_p4block_column, +}; + +static struct wargp_option update_opts[] = { + { + .name = "block entry", + .key = ARGP_KEY_ARG, + .doc = "IPv4 transport address block", + .offset = offsetof(struct update_args, blk), + .type = &wt_p4block, + }, + { 0 }, +}; + +static int handle_p4block_update(char *iname, int argc, char **argv, + struct jool_result (*cb)(struct joolnl_socket *, char const *, struct p4block const *)) +{ + struct update_args uargs = { 0 }; + struct joolnl_socket sk; + struct jool_result result; + + result.error = wargp_parse(update_opts, argc, argv, &uargs); + if (result.error) + return result.error; + + result = joolnl_setup(&sk, xt_get()); + if (result.error) + return pr_result(&result); + + result = cb(&sk, iname, &uargs.blk); + + joolnl_teardown(&sk); + return pr_result(&result); +} + +int handle_p4block_add(char *iname, int argc, char **argv, void const *arg) +{ + return handle_p4block_update(iname, argc, argv, joolnl_p4block_add); +} + +void autocomplete_p4block_add(void const *args) +{ + print_wargp_opts(update_opts); +} + +int handle_p4block_remove(char *iname, int argc, char **argv, void const *arg) +{ + return handle_p4block_update(iname, argc, argv, joolnl_p4block_rm); +} + +void autocomplete_p4block_remove(void const *args) +{ + print_wargp_opts(update_opts); +} diff --git a/src/usr/argp/wargp/p4block.h b/src/usr/argp/wargp/p4block.h new file mode 100644 index 000000000..0cfbd2134 --- /dev/null +++ b/src/usr/argp/wargp/p4block.h @@ -0,0 +1,12 @@ +#ifndef SRC_USR_ARGP_WARGP_P4BLOCK_H_ +#define SRC_USR_ARGP_WARGP_P4BLOCK_H_ + +int handle_p4block_display(char *iname, int argc, char **argv, void const *arg); +int handle_p4block_add(char *iname, int argc, char **argv, void const *arg); +int handle_p4block_remove(char *iname, int argc, char **argv, void const *arg); + +void autocomplete_p4block_display(void const *args); +void autocomplete_p4block_add(void const *args); +void autocomplete_p4block_remove(void const *args); + +#endif /* SRC_USR_ARGP_WARGP_P4BLOCK_H_ */ diff --git a/src/usr/nl/Makefile.am b/src/usr/nl/Makefile.am index 38600b76e..83d65571d 100644 --- a/src/usr/nl/Makefile.am +++ b/src/usr/nl/Makefile.am @@ -13,6 +13,7 @@ libjoolnl_la_SOURCES = \ instance.c instance.h \ joold.c joold.h \ json.c json.h \ + p4block.c p4block.h \ pool4.c pool4.h \ session.c session.h \ stats.c stats.h \ diff --git a/src/usr/nl/attribute.c b/src/usr/nl/attribute.c index 0912f483f..6661579ae 100644 --- a/src/usr/nl/attribute.c +++ b/src/usr/nl/attribute.c @@ -491,6 +491,27 @@ int nla_put_pool4(struct nl_msg *msg, int attrtype, struct pool4_entry const *en return -NLE_NOMEM; } +int nla_put_p4block(struct nl_msg *msg, int attrtype, struct p4block const *blk) +{ + struct nlattr *root; + + root = jnla_nest_start(msg, attrtype); + if (!root) + return -NLE_NOMEM; + + if (nla_put_addr4(msg, JNLAPB_ADDR, &blk->addr) < 0) + goto nla_put_failure; + NLA_PUT_U16(msg, JNLAPB_PORT_MIN, blk->ports.min); + NLA_PUT_U16(msg, JNLAPB_PORT_MAX, blk->ports.max); + + nla_nest_end(msg, root); + return 0; + +nla_put_failure: + nla_nest_cancel(msg, root); + return -NLE_NOMEM; +} + int nla_put_bib_attrs(struct nl_msg *msg, int attrtype, struct ipv6_transport_addr const *addr6, struct ipv4_transport_addr const *addr4, diff --git a/src/usr/nl/attribute.h b/src/usr/nl/attribute.h index 7d33fdfc0..4f89becc5 100644 --- a/src/usr/nl/attribute.h +++ b/src/usr/nl/attribute.h @@ -65,6 +65,7 @@ int nla_put_prefix4(struct nl_msg *msg, int attrtype, struct ipv4_prefix const * int nla_put_plateaus(struct nl_msg *msg, int attrtype, struct mtu_plateaus const *plateaus); int nla_put_eam(struct nl_msg *msg, int attrtype, struct eamt_entry const *entry); int nla_put_pool4(struct nl_msg *msg, int attrtype, struct pool4_entry const *entry); +int nla_put_p4block(struct nl_msg *msg, int attrtype, struct p4block const *blk); int nla_put_bib(struct nl_msg *msg, int attrtype, struct bib_entry const *entry); int nla_put_bib_attrs(struct nl_msg *msg, int attrtype, struct ipv6_transport_addr const *addr6, diff --git a/src/usr/nl/eamt.c b/src/usr/nl/eamt.c index de95be50d..f906fd6e2 100644 --- a/src/usr/nl/eamt.c +++ b/src/usr/nl/eamt.c @@ -88,6 +88,8 @@ static struct jool_result __update(struct joolnl_socket *sk, char const *iname, if (result.error) return result; + /* TODO why is this code not using nla_put_eam()? */ + root = jnla_nest_start(msg, JNLAR_OPERAND); if (!root) goto nla_put_failure; diff --git a/src/usr/nl/p4block.c b/src/usr/nl/p4block.c new file mode 100644 index 000000000..13975633d --- /dev/null +++ b/src/usr/nl/p4block.c @@ -0,0 +1,49 @@ +#include "usr/nl/p4block.h" + +#include +#include +#include "usr/nl/attribute.h" +#include "usr/nl/common.h" + +struct jool_result joolnl_p4block_foreach(struct joolnl_socket *sk, + char const *iname) +{ + struct nl_msg *msg; + struct jool_result result; + + result = joolnl_alloc_msg(sk, iname, JNLOP_P4BLOCK_FOREACH, 0, &msg); + if (result.error) + return result; + + return joolnl_request(sk, msg, NULL, NULL); +} + +static struct jool_result __update(struct joolnl_socket *sk, char const *iname, + enum joolnl_operation operation, struct p4block const *blk) +{ + struct nl_msg *msg; + struct jool_result result; + + result = joolnl_alloc_msg(sk, iname, operation, 0, &msg); + if (result.error) + return result; + + if (nla_put_p4block(msg, JNLAR_OPERAND, blk) < 0) { + nlmsg_free(msg); + return joolnl_err_msgsize(); + } + + return joolnl_request(sk, msg, NULL, NULL); +} + +struct jool_result joolnl_p4block_add(struct joolnl_socket *sk, + char const *iname, struct p4block const *blk) +{ + return __update(sk, iname, JNLOP_P4BLOCK_ADD, blk); +} + +struct jool_result joolnl_p4block_rm(struct joolnl_socket *sk, + char const *iname, struct p4block const *blk) +{ + return __update(sk, iname, JNLOP_P4BLOCK_RM, blk); +} diff --git a/src/usr/nl/p4block.h b/src/usr/nl/p4block.h new file mode 100644 index 000000000..3cbeaadf5 --- /dev/null +++ b/src/usr/nl/p4block.h @@ -0,0 +1,24 @@ +#ifndef SRC_USR_NL_P4BLOCK_H_ +#define SRC_USR_NL_P4BLOCK_H_ + +#include "common/config.h" +#include "usr/nl/core.h" + +struct jool_result joolnl_p4block_foreach( + struct joolnl_socket *sk, + char const *iname +); + +struct jool_result joolnl_p4block_add( + struct joolnl_socket *sk, + char const *iname, + struct p4block const *blk +); + +struct jool_result joolnl_p4block_rm( + struct joolnl_socket *sk, + char const *iname, + struct p4block const *blk +); + +#endif /* SRC_USR_NL_P4BLOCK_H_ */ diff --git a/test/unit/pool4db/Makefile b/test/unit/pool4db/Makefile index 485da79d8..7a7293618 100644 --- a/test/unit/pool4db/Makefile +++ b/test/unit/pool4db/Makefile @@ -24,6 +24,7 @@ $(UNIT)-objs += ../../../src/mod/common/wrapper-global.o $(UNIT)-objs += ../../../src/mod/common/db/global.o $(UNIT)-objs += ../../../src/mod/common/db/rbtree.o $(UNIT)-objs += ../../../src/mod/common/db/pool4/empty.o +$(UNIT)-objs += ../../../src/mod/common/db/pool4-v2/block.o $(UNIT)-objs += ../../../src/mod/common/nl/attribute.o $(UNIT)-objs += ../impersonator/route.o $(UNIT)-objs += impersonator.o diff --git a/test/unit/pool4db/pool4db_test.c b/test/unit/pool4db/pool4db_test.c index d310832a5..8a41b7228 100644 --- a/test/unit/pool4db/pool4db_test.c +++ b/test/unit/pool4db/pool4db_test.c @@ -518,6 +518,152 @@ static bool test_flush(void) return success; } +static bool validate_masks(struct mask_domain *masks, const char *expected) +{ + struct ipv4_transport_addr actual; + bool consecutive; + unsigned int a; + bool success; + + a = 0; + success = true; + + pr_debug("Mask domain:\n"); + while (mask_domain_next(masks, &actual, &consecutive) == 0) { + pr_debug(" %pI4:%u\n", &actual.l3, actual.l4); + success &= ASSERT_ADDR4(expected, &actual.l3, "addr4"); + a++; + } + success &= ASSERT_UINT(5, a, "total transport addresses"); + + return success; +} + +#define TARGET(a, b) __mask_domain_find_block(blocks, a, b) + +static bool test_block(void) +{ + struct p4blocks *blocks; + struct p4block blk1, blk2, blk3, blk4; + struct in6_addr src; + struct mask_domain *masks; + bool success = true; + + blocks = p4block_init(); + success &= ASSERT_BOOL(true, blocks != NULL, "p4block init"); + if (!success) + return false; + + memset(&src, 0, sizeof(src)); + + /* Try empty database */ + + src.s6_addr16[7] = cpu_to_be16(1); + success &= ASSERT_UINT(JSTAT_UNKNOWN, TARGET(&src, &masks), "jstat 0"); + + p4block_print(blocks, "Should print empty"); + + /* Populate database */ + + blk1.addr.s_addr = cpu_to_be32(0xc0000201); + blk1.ports.min = 10; + blk1.ports.max = 14; + success &= ASSERT_INT(0, p4block_add(blocks, &blk1), "add 1"); + + blk2.addr.s_addr = cpu_to_be32(0xc0000202); + blk2.ports.min = 15; + blk2.ports.max = 19; + success &= ASSERT_INT(0, p4block_add(blocks, &blk2), "add 2"); + + blk3.addr.s_addr = cpu_to_be32(0xc0000203); + blk3.ports.min = 20; + blk3.ports.max = 24; + success &= ASSERT_INT(0, p4block_add(blocks, &blk3), "add 3"); + + blk4.addr.s_addr = cpu_to_be32(0xc0000204); + blk4.ports.min = 25; + blk4.ports.max = 29; + success &= ASSERT_INT(0, p4block_add(blocks, &blk4), "add 4"); + + p4block_print(blocks, "All entries recently added"); + + /* Try populated database */ + + src.s6_addr16[7] = cpu_to_be16(1); + success &= ASSERT_UINT(JSTAT_SUCCESS, TARGET(&src, &masks), "jstat 1"); + validate_masks(masks, "192.0.2.1"); + mask_domain_put(masks); + + src.s6_addr16[7] = cpu_to_be16(2); + success &= ASSERT_UINT(JSTAT_SUCCESS, TARGET(&src, &masks), "jstat 2"); + validate_masks(masks, "192.0.2.2"); + mask_domain_put(masks); + + p4block_print(blocks, "Assigned two entries"); + + src.s6_addr16[7] = cpu_to_be16(3); + success &= ASSERT_UINT(JSTAT_SUCCESS, TARGET(&src, &masks), "jstat 3"); + validate_masks(masks, "192.0.2.3"); + mask_domain_put(masks); + + src.s6_addr16[7] = cpu_to_be16(4); + success &= ASSERT_UINT(JSTAT_SUCCESS, TARGET(&src, &masks), "jstat 4"); + validate_masks(masks, "192.0.2.4"); + mask_domain_put(masks); + + src.s6_addr16[7] = cpu_to_be16(5); + success &= ASSERT_UINT(JSTAT_UNKNOWN, TARGET(&src, &masks), "jstat 5"); + + p4block_print(blocks, "Assigned all entries"); + + /* Try already assigned blocks */ + + src.s6_addr16[7] = cpu_to_be16(2); + success &= ASSERT_UINT(JSTAT_SUCCESS, TARGET(&src, &masks), "jstat 2"); + validate_masks(masks, "192.0.2.2"); + mask_domain_put(masks); + + src.s6_addr16[7] = cpu_to_be16(1); + success &= ASSERT_UINT(JSTAT_SUCCESS, TARGET(&src, &masks), "jstat 1"); + validate_masks(masks, "192.0.2.1"); + mask_domain_put(masks); + + src.s6_addr16[7] = cpu_to_be16(4); + success &= ASSERT_UINT(JSTAT_SUCCESS, TARGET(&src, &masks), "jstat 4"); + validate_masks(masks, "192.0.2.4"); + mask_domain_put(masks); + + src.s6_addr16[7] = cpu_to_be16(3); + success &= ASSERT_UINT(JSTAT_SUCCESS, TARGET(&src, &masks), "jstat 3"); + validate_masks(masks, "192.0.2.3"); + mask_domain_put(masks); + + /* Try rm() */ + + success &= ASSERT_INT(0, p4block_rm(blocks, &blk1), "rm 1"); + success &= ASSERT_INT(0, p4block_rm(blocks, &blk3), "rm 2"); + success &= ASSERT_INT(-ESRCH, p4block_rm(blocks, &blk1), "rm 3"); + success &= ASSERT_INT(-ESRCH, p4block_rm(blocks, &blk3), "rm 4"); + + p4block_print(blocks, "Removed 2 blocks"); + + /* Try expire() */ + + success &= ASSERT_INT(0, p4block_add(blocks, &blk1), "add 5"); + success &= ASSERT_INT(0, p4block_add(blocks, &blk3), "add 6"); + p4block_expire(blocks, 10000); + + p4block_print(blocks, "Added blocks back, expired nothing"); + + p4block_cheat(blocks); + p4block_expire(blocks, 10000); + + p4block_print(blocks, "All nodes should be clear"); + + p4block_put(blocks); + return success; +} + static int init(void) { pool = pool4db_alloc(); @@ -559,6 +705,7 @@ int init_module(void) test_group_test(&test, test_add, "Add"); test_group_test(&test, test_rm, "Rm"); test_group_test(&test, test_flush, "Flush"); + test_group_test(&test, test_block, "Block"); return test_group_end(&test); }